mirror of
https://github.com/starovoid/rxing.git
synced 2026-07-27 21:02:35 +00:00
checkin for entire port source tree
This commit is contained in:
55
port_src/output/zxing/aztec/aztec_detector_result.rs
Normal file
55
port_src/output/zxing/aztec/aztec_detector_result.rs
Normal file
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* 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::aztec;
|
||||
|
||||
/**
|
||||
* <p>Extends {@link DetectorResult} with more information specific to the Aztec format,
|
||||
* like the number of layers and whether it's compact.</p>
|
||||
*
|
||||
* @author Sean Owen
|
||||
*/
|
||||
pub struct AztecDetectorResult {
|
||||
super: DetectorResult;
|
||||
|
||||
let compact: bool;
|
||||
|
||||
let nb_datablocks: i32;
|
||||
|
||||
let nb_layers: i32;
|
||||
}
|
||||
|
||||
impl AztecDetectorResult {
|
||||
|
||||
pub fn new( bits: &BitMatrix, points: &Vec<ResultPoint>, compact: bool, nb_datablocks: i32, nb_layers: i32) -> AztecDetectorResult {
|
||||
super(bits, points);
|
||||
let .compact = compact;
|
||||
let .nbDatablocks = nb_datablocks;
|
||||
let .nbLayers = nb_layers;
|
||||
}
|
||||
|
||||
pub fn get_nb_layers(&self) -> i32 {
|
||||
return self.nb_layers;
|
||||
}
|
||||
|
||||
pub fn get_nb_datablocks(&self) -> i32 {
|
||||
return self.nb_datablocks;
|
||||
}
|
||||
|
||||
pub fn is_compact(&self) -> bool {
|
||||
return self.compact;
|
||||
}
|
||||
}
|
||||
|
||||
111
port_src/output/zxing/aztec/aztec_reader.rs
Normal file
111
port_src/output/zxing/aztec/aztec_reader.rs
Normal file
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* 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::aztec;
|
||||
|
||||
/**
|
||||
* This implementation can detect and decode Aztec codes in an image.
|
||||
*
|
||||
* @author David Olivier
|
||||
*/
|
||||
#[derive(Reader)]
|
||||
pub struct AztecReader {
|
||||
}
|
||||
|
||||
impl AztecReader {
|
||||
|
||||
/**
|
||||
* Locates and decodes a Data Matrix code in an image.
|
||||
*
|
||||
* @return a String representing the content encoded by the Data Matrix code
|
||||
* @throws NotFoundException if a Data Matrix code cannot be found
|
||||
* @throws FormatException if a Data Matrix code cannot be decoded
|
||||
*/
|
||||
pub fn decode(&self, image: &BinaryBitmap) -> /* throws NotFoundException, FormatException */Result<Result, Rc<Exception>> {
|
||||
return Ok(self.decode(image, null));
|
||||
}
|
||||
|
||||
pub fn decode(&self, image: &BinaryBitmap, hints: &Map<DecodeHintType, ?>) -> /* throws NotFoundException, FormatException */Result<Result, Rc<Exception>> {
|
||||
let not_found_exception: NotFoundException = null;
|
||||
let format_exception: FormatException = null;
|
||||
let detector: Detector = Detector::new(&image.get_black_matrix());
|
||||
let mut points: Vec<ResultPoint> = null;
|
||||
let decoder_result: DecoderResult = null;
|
||||
let tryResult1 = 0;
|
||||
'try1: loop {
|
||||
{
|
||||
let detector_result: AztecDetectorResult = detector.detect(false);
|
||||
points = detector_result.get_points();
|
||||
decoder_result = Decoder::new().decode(detector_result);
|
||||
}
|
||||
break 'try1
|
||||
}
|
||||
match tryResult1 {
|
||||
catch ( e: &NotFoundException) {
|
||||
not_found_exception = e;
|
||||
} catch ( e: &FormatException) {
|
||||
format_exception = e;
|
||||
} 0 => break
|
||||
}
|
||||
|
||||
if decoder_result == null {
|
||||
let tryResult1 = 0;
|
||||
'try1: loop {
|
||||
{
|
||||
let detector_result: AztecDetectorResult = detector.detect(true);
|
||||
points = detector_result.get_points();
|
||||
decoder_result = Decoder::new().decode(detector_result);
|
||||
}
|
||||
break 'try1
|
||||
}
|
||||
match tryResult1 {
|
||||
catch ( e: &NotFoundExceptionFormatException | ) {
|
||||
if not_found_exception != null {
|
||||
throw not_found_exception;
|
||||
}
|
||||
if format_exception != null {
|
||||
throw format_exception;
|
||||
}
|
||||
throw e;
|
||||
} 0 => break
|
||||
}
|
||||
|
||||
}
|
||||
if hints != null {
|
||||
let rpcb: ResultPointCallback = hints.get(DecodeHintType::NEED_RESULT_POINT_CALLBACK) as ResultPointCallback;
|
||||
if rpcb != null {
|
||||
for let point: ResultPoint in points {
|
||||
rpcb.found_possible_result_point(point);
|
||||
}
|
||||
}
|
||||
}
|
||||
let result: Result = Result::new(&decoder_result.get_text(), &decoder_result.get_raw_bytes(), &decoder_result.get_num_bits(), points, BarcodeFormat::AZTEC, &System::current_time_millis());
|
||||
let byte_segments: List<Vec<i8>> = decoder_result.get_byte_segments();
|
||||
if byte_segments != null {
|
||||
result.put_metadata(ResultMetadataType::BYTE_SEGMENTS, &byte_segments);
|
||||
}
|
||||
let ec_level: String = decoder_result.get_e_c_level();
|
||||
if ec_level != null {
|
||||
result.put_metadata(ResultMetadataType::ERROR_CORRECTION_LEVEL, &ec_level);
|
||||
}
|
||||
result.put_metadata(ResultMetadataType::SYMBOLOGY_IDENTIFIER, format!("]z{}", decoder_result.get_symbology_modifier()));
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
pub fn reset(&self) {
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
|
||||
98
port_src/output/zxing/aztec/aztec_writer.rs
Normal file
98
port_src/output/zxing/aztec/aztec_writer.rs
Normal file
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* 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::aztec;
|
||||
|
||||
/**
|
||||
* Renders an Aztec code as a {@link BitMatrix}.
|
||||
*/
|
||||
#[derive(Writer)]
|
||||
pub struct AztecWriter {
|
||||
}
|
||||
|
||||
impl AztecWriter {
|
||||
|
||||
pub fn encode(&self, contents: &String, format: &BarcodeFormat, width: i32, height: i32) -> BitMatrix {
|
||||
return ::encode(&contents, format, width, height, null);
|
||||
}
|
||||
|
||||
pub fn encode(&self, contents: &String, format: &BarcodeFormat, width: i32, height: i32, hints: &Map<EncodeHintType, ?>) -> BitMatrix {
|
||||
// Do not add any ECI code by default
|
||||
let mut charset: Charset = null;
|
||||
let ecc_percent: i32 = Encoder::DEFAULT_EC_PERCENT;
|
||||
let mut layers: i32 = Encoder::DEFAULT_AZTEC_LAYERS;
|
||||
if hints != null {
|
||||
if hints.contains_key(EncodeHintType::CHARACTER_SET) {
|
||||
charset = Charset::for_name(&hints.get(EncodeHintType::CHARACTER_SET).to_string());
|
||||
}
|
||||
if hints.contains_key(EncodeHintType::ERROR_CORRECTION) {
|
||||
ecc_percent = Integer::parse_int(&hints.get(EncodeHintType::ERROR_CORRECTION).to_string());
|
||||
}
|
||||
if hints.contains_key(EncodeHintType::AZTEC_LAYERS) {
|
||||
layers = Integer::parse_int(&hints.get(EncodeHintType::AZTEC_LAYERS).to_string());
|
||||
}
|
||||
}
|
||||
return ::encode(&contents, format, width, height, &charset, ecc_percent, layers);
|
||||
}
|
||||
|
||||
fn encode( contents: &String, format: &BarcodeFormat, width: i32, height: i32, charset: &Charset, ecc_percent: i32, layers: i32) -> BitMatrix {
|
||||
if format != BarcodeFormat::AZTEC {
|
||||
throw IllegalArgumentException::new(format!("Can only encode AZTEC, but got {}", format));
|
||||
}
|
||||
let aztec: AztecCode = Encoder::encode(&contents, ecc_percent, layers, &charset);
|
||||
return ::render_result(aztec, width, height);
|
||||
}
|
||||
|
||||
fn render_result( code: &AztecCode, width: i32, height: i32) -> BitMatrix {
|
||||
let input: BitMatrix = code.get_matrix();
|
||||
if input == null {
|
||||
throw IllegalStateException::new();
|
||||
}
|
||||
let input_width: i32 = input.get_width();
|
||||
let input_height: i32 = input.get_height();
|
||||
let output_width: i32 = Math::max(width, input_width);
|
||||
let output_height: i32 = Math::max(height, input_height);
|
||||
let multiple: i32 = Math::min(output_width / input_width, output_height / input_height);
|
||||
let left_padding: i32 = (output_width - (input_width * multiple)) / 2;
|
||||
let top_padding: i32 = (output_height - (input_height * multiple)) / 2;
|
||||
let output: BitMatrix = BitMatrix::new(output_width, output_height);
|
||||
{
|
||||
let input_y: i32 = 0, let output_y: i32 = top_padding;
|
||||
while input_y < input_height {
|
||||
{
|
||||
// Write the contents of this row of the barcode
|
||||
{
|
||||
let input_x: i32 = 0, let output_x: i32 = left_padding;
|
||||
while input_x < input_width {
|
||||
{
|
||||
if input.get(input_x, input_y) {
|
||||
output.set_region(output_x, output_y, multiple, multiple);
|
||||
}
|
||||
}
|
||||
input_x += 1;
|
||||
output_x += multiple;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
input_y += 1;
|
||||
output_y += multiple;
|
||||
}
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
}
|
||||
|
||||
556
port_src/output/zxing/aztec/decoder/decoder.rs
Normal file
556
port_src/output/zxing/aztec/decoder/decoder.rs
Normal file
@@ -0,0 +1,556 @@
|
||||
/*
|
||||
* 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::aztec::decoder;
|
||||
|
||||
/**
|
||||
* <p>The main class which implements Aztec Code decoding -- as opposed to locating and extracting
|
||||
* the Aztec Code from an image.</p>
|
||||
*
|
||||
* @author David Olivier
|
||||
*/
|
||||
|
||||
const UPPER_TABLE: vec![Vec<String>; 32] = vec!["CTRL_PS", " ", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "CTRL_LL", "CTRL_ML", "CTRL_DL", "CTRL_BS", ]
|
||||
;
|
||||
|
||||
const LOWER_TABLE: vec![Vec<String>; 32] = vec!["CTRL_PS", " ", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "CTRL_US", "CTRL_ML", "CTRL_DL", "CTRL_BS", ]
|
||||
;
|
||||
|
||||
const MIXED_TABLE: vec![Vec<String>; 32] = vec!["CTRL_PS", " ", "\1", "\2", "\3", "\4", "\5", "\6", "\7", "\b", "\t", "\n", "\13", "\f", "\r", "\33", "\34", "\35", "\36", "\37", "@", "\\", "^", "_", "`", "|", "~", "\177", "CTRL_LL", "CTRL_UL", "CTRL_PL", "CTRL_BS", ]
|
||||
;
|
||||
|
||||
const PUNCT_TABLE: vec![Vec<String>; 32] = vec!["FLG(n)", "\r", "\r\n", ". ", ", ", ": ", "!", "\"", "#", "$", "%", "&", "'", "(", ")", "*", "+", ",", "-", ".", "/", ":", ";", "<", "=", ">", "?", "[", "]", "{", "}", "CTRL_UL", ]
|
||||
;
|
||||
|
||||
const DIGIT_TABLE: vec![Vec<String>; 16] = vec!["CTRL_PS", " ", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", ",", ".", "CTRL_UL", "CTRL_US", ]
|
||||
;
|
||||
|
||||
const DEFAULT_ENCODING: Charset = StandardCharsets::ISO_8859_1;
|
||||
pub struct Decoder {
|
||||
|
||||
let mut ddata: AztecDetectorResult;
|
||||
}
|
||||
|
||||
impl Decoder {
|
||||
|
||||
enum Table {
|
||||
|
||||
UPPER(), LOWER(), MIXED(), DIGIT(), PUNCT(), BINARY()
|
||||
}
|
||||
|
||||
pub fn decode(&self, detector_result: &AztecDetectorResult) -> /* throws FormatException */Result<DecoderResult, Rc<Exception>> {
|
||||
self.ddata = detector_result;
|
||||
let matrix: BitMatrix = detector_result.get_bits();
|
||||
let rawbits: Vec<bool> = self.extract_bits(matrix);
|
||||
let corrected_bits: CorrectedBitsResult = self.correct_bits(&rawbits);
|
||||
let raw_bytes: Vec<i8> = ::convert_bool_array_to_byte_array(corrected_bits.correctBits);
|
||||
let result: String = ::get_encoded_data(corrected_bits.correctBits);
|
||||
let decoder_result: DecoderResult = DecoderResult::new(&raw_bytes, &result, null, &String::format("%d%%", corrected_bits.ecLevel));
|
||||
decoder_result.set_num_bits(corrected_bits.correctBits.len());
|
||||
return Ok(decoder_result);
|
||||
}
|
||||
|
||||
// This method is used for testing the high-level encoder
|
||||
pub fn high_level_decode( corrected_bits: &Vec<bool>) -> /* throws FormatException */Result<String, Rc<Exception>> {
|
||||
return Ok(::get_encoded_data(&corrected_bits));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the string encoded in the aztec code bits
|
||||
*
|
||||
* @return the decoded string
|
||||
*/
|
||||
fn get_encoded_data( corrected_bits: &Vec<bool>) -> /* throws FormatException */Result<String, Rc<Exception>> {
|
||||
let end_index: i32 = corrected_bits.len();
|
||||
// table most recently latched to
|
||||
let latch_table: Table = Table::UPPER;
|
||||
// table to use for the next read
|
||||
let shift_table: Table = Table::UPPER;
|
||||
// Final decoded string result
|
||||
// (correctedBits-5) / 4 is an upper bound on the size (all-digit result)
|
||||
let result: StringBuilder = StringBuilder::new((corrected_bits.len() - 5) / 4);
|
||||
// Intermediary buffer of decoded bytes, which is decoded into a string and flushed
|
||||
// when character encoding changes (ECI) or input ends.
|
||||
let decoded_bytes: ByteArrayOutputStream = ByteArrayOutputStream::new();
|
||||
let mut encoding: Charset = DEFAULT_ENCODING;
|
||||
let mut index: i32 = 0;
|
||||
while index < end_index {
|
||||
if shift_table == Table::BINARY {
|
||||
if end_index - index < 5 {
|
||||
break;
|
||||
}
|
||||
let mut length: i32 = ::read_code(&corrected_bits, index, 5);
|
||||
index += 5;
|
||||
if length == 0 {
|
||||
if end_index - index < 11 {
|
||||
break;
|
||||
}
|
||||
length = ::read_code(&corrected_bits, index, 11) + 31;
|
||||
index += 11;
|
||||
}
|
||||
{
|
||||
let char_count: i32 = 0;
|
||||
while char_count < length {
|
||||
{
|
||||
if end_index - index < 8 {
|
||||
// Force outer loop to exit
|
||||
index = end_index;
|
||||
break;
|
||||
}
|
||||
let code: i32 = ::read_code(&corrected_bits, index, 8);
|
||||
decoded_bytes.write(code as i8);
|
||||
index += 8;
|
||||
}
|
||||
char_count += 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Go back to whatever mode we had been in
|
||||
shift_table = latch_table;
|
||||
} else {
|
||||
let size: i32 = if shift_table == Table::DIGIT { 4 } else { 5 };
|
||||
if end_index - index < size {
|
||||
break;
|
||||
}
|
||||
let code: i32 = ::read_code(&corrected_bits, index, size);
|
||||
index += size;
|
||||
let str: String = ::get_character(shift_table, code);
|
||||
if "FLG(n)".equals(&str) {
|
||||
if end_index - index < 3 {
|
||||
break;
|
||||
}
|
||||
let mut n: i32 = ::read_code(&corrected_bits, index, 3);
|
||||
index += 3;
|
||||
// flush bytes, FLG changes state
|
||||
let tryResult1 = 0;
|
||||
'try1: loop {
|
||||
{
|
||||
result.append(&decoded_bytes.to_string(&encoding.name()));
|
||||
}
|
||||
break 'try1
|
||||
}
|
||||
match tryResult1 {
|
||||
catch ( uee: &UnsupportedEncodingException) {
|
||||
throw IllegalStateException::new(&uee);
|
||||
} 0 => break
|
||||
}
|
||||
|
||||
decoded_bytes.reset();
|
||||
match n {
|
||||
0 =>
|
||||
{
|
||||
// translate FNC1 as ASCII 29
|
||||
result.append(29 as char);
|
||||
break;
|
||||
}
|
||||
7 =>
|
||||
{
|
||||
// FLG(7) is reserved and illegal
|
||||
throw FormatException::get_format_instance();
|
||||
}
|
||||
_ =>
|
||||
{
|
||||
// ECI is decimal integer encoded as 1-6 codes in DIGIT mode
|
||||
let mut eci: i32 = 0;
|
||||
if end_index - index < 4 * n {
|
||||
break;
|
||||
}
|
||||
while n -= 1 !!!check!!! post decrement > 0 {
|
||||
let next_digit: i32 = ::read_code(&corrected_bits, index, 4);
|
||||
index += 4;
|
||||
if next_digit < 2 || next_digit > 11 {
|
||||
// Not a decimal digit
|
||||
throw FormatException::get_format_instance();
|
||||
}
|
||||
eci = eci * 10 + (next_digit - 2);
|
||||
}
|
||||
let charset_e_c_i: CharacterSetECI = CharacterSetECI::get_character_set_e_c_i_by_value(eci);
|
||||
if charset_e_c_i == null {
|
||||
throw FormatException::get_format_instance();
|
||||
}
|
||||
encoding = charset_e_c_i.get_charset();
|
||||
}
|
||||
}
|
||||
// Go back to whatever mode we had been in
|
||||
shift_table = latch_table;
|
||||
} else if str.starts_with("CTRL_") {
|
||||
// Table changes
|
||||
// ISO/IEC 24778:2008 prescribes ending a shift sequence in the mode from which it was invoked.
|
||||
// That's including when that mode is a shift.
|
||||
// Our test case dlusbs.png for issue #642 exercises that.
|
||||
// Latch the current mode, so as to return to Upper after U/S B/S
|
||||
latch_table = shift_table;
|
||||
shift_table = ::get_table(&str.char_at(5));
|
||||
if str.char_at(6) == 'L' {
|
||||
latch_table = shift_table;
|
||||
}
|
||||
} else {
|
||||
// Though stored as a table of strings for convenience, codes actually represent 1 or 2 *bytes*.
|
||||
let b: Vec<i8> = str.get_bytes(StandardCharsets::US_ASCII);
|
||||
decoded_bytes.write(&b, 0, b.len());
|
||||
// Go back to whatever mode we had been in
|
||||
shift_table = latch_table;
|
||||
}
|
||||
}
|
||||
}
|
||||
let tryResult1 = 0;
|
||||
'try1: loop {
|
||||
{
|
||||
result.append(&decoded_bytes.to_string(&encoding.name()));
|
||||
}
|
||||
break 'try1
|
||||
}
|
||||
match tryResult1 {
|
||||
catch ( uee: &UnsupportedEncodingException) {
|
||||
throw IllegalStateException::new(&uee);
|
||||
} 0 => break
|
||||
}
|
||||
|
||||
return Ok(result.to_string());
|
||||
}
|
||||
|
||||
/**
|
||||
* gets the table corresponding to the char passed
|
||||
*/
|
||||
fn get_table( t: char) -> Table {
|
||||
match t {
|
||||
'L' =>
|
||||
{
|
||||
return Table::LOWER;
|
||||
}
|
||||
'P' =>
|
||||
{
|
||||
return Table::PUNCT;
|
||||
}
|
||||
'M' =>
|
||||
{
|
||||
return Table::MIXED;
|
||||
}
|
||||
'D' =>
|
||||
{
|
||||
return Table::DIGIT;
|
||||
}
|
||||
'B' =>
|
||||
{
|
||||
return Table::BINARY;
|
||||
}
|
||||
'U' =>
|
||||
{
|
||||
}
|
||||
_ =>
|
||||
{
|
||||
return Table::UPPER;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the character (or string) corresponding to the passed code in the given table
|
||||
*
|
||||
* @param table the table used
|
||||
* @param code the code of the character
|
||||
*/
|
||||
fn get_character( table: &Table, code: i32) -> String {
|
||||
match table {
|
||||
UPPER =>
|
||||
{
|
||||
return UPPER_TABLE[code];
|
||||
}
|
||||
LOWER =>
|
||||
{
|
||||
return LOWER_TABLE[code];
|
||||
}
|
||||
MIXED =>
|
||||
{
|
||||
return MIXED_TABLE[code];
|
||||
}
|
||||
PUNCT =>
|
||||
{
|
||||
return PUNCT_TABLE[code];
|
||||
}
|
||||
DIGIT =>
|
||||
{
|
||||
return DIGIT_TABLE[code];
|
||||
}
|
||||
_ =>
|
||||
{
|
||||
// Should not reach here.
|
||||
throw IllegalStateException::new("Bad table");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct CorrectedBitsResult {
|
||||
|
||||
let correct_bits: Vec<bool>;
|
||||
|
||||
let ec_level: i32;
|
||||
}
|
||||
|
||||
impl CorrectedBitsResult {
|
||||
|
||||
fn new( correct_bits: &Vec<bool>, ec_level: i32) -> CorrectedBitsResult {
|
||||
let .correctBits = correct_bits;
|
||||
let .ecLevel = ec_level;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* <p>Performs RS error correction on an array of bits.</p>
|
||||
*
|
||||
* @return the corrected array
|
||||
* @throws FormatException if the input contains too many errors
|
||||
*/
|
||||
fn correct_bits(&self, rawbits: &Vec<bool>) -> /* throws FormatException */Result<CorrectedBitsResult, Rc<Exception>> {
|
||||
let mut gf: GenericGF;
|
||||
let codeword_size: i32;
|
||||
if self.ddata.get_nb_layers() <= 2 {
|
||||
codeword_size = 6;
|
||||
gf = GenericGF::AZTEC_DATA_6;
|
||||
} else if self.ddata.get_nb_layers() <= 8 {
|
||||
codeword_size = 8;
|
||||
gf = GenericGF::AZTEC_DATA_8;
|
||||
} else if self.ddata.get_nb_layers() <= 22 {
|
||||
codeword_size = 10;
|
||||
gf = GenericGF::AZTEC_DATA_10;
|
||||
} else {
|
||||
codeword_size = 12;
|
||||
gf = GenericGF::AZTEC_DATA_12;
|
||||
}
|
||||
let num_data_codewords: i32 = self.ddata.get_nb_datablocks();
|
||||
let num_codewords: i32 = rawbits.len() / codeword_size;
|
||||
if num_codewords < num_data_codewords {
|
||||
throw FormatException::get_format_instance();
|
||||
}
|
||||
let mut offset: i32 = rawbits.len() % codeword_size;
|
||||
let data_words: [i32; num_codewords] = [0; num_codewords];
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < num_codewords {
|
||||
{
|
||||
data_words[i] = ::read_code(&rawbits, offset, codeword_size);
|
||||
}
|
||||
i += 1;
|
||||
offset += codeword_size;
|
||||
}
|
||||
}
|
||||
|
||||
let tryResult1 = 0;
|
||||
'try1: loop {
|
||||
{
|
||||
let rs_decoder: ReedSolomonDecoder = ReedSolomonDecoder::new(gf);
|
||||
rs_decoder.decode(&data_words, num_codewords - num_data_codewords);
|
||||
}
|
||||
break 'try1
|
||||
}
|
||||
match tryResult1 {
|
||||
catch ( ex: &ReedSolomonException) {
|
||||
throw FormatException::get_format_instance(ex);
|
||||
} 0 => break
|
||||
}
|
||||
|
||||
// Now perform the unstuffing operation.
|
||||
// First, count how many bits are going to be thrown out as stuffing
|
||||
let mask: i32 = (1 << codeword_size) - 1;
|
||||
let stuffed_bits: i32 = 0;
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < num_data_codewords {
|
||||
{
|
||||
let data_word: i32 = data_words[i];
|
||||
if data_word == 0 || data_word == mask {
|
||||
throw FormatException::get_format_instance();
|
||||
} else if data_word == 1 || data_word == mask - 1 {
|
||||
stuffed_bits += 1;
|
||||
}
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Now, actually unpack the bits and remove the stuffing
|
||||
let corrected_bits: [bool; num_data_codewords * codeword_size - stuffed_bits] = [false; num_data_codewords * codeword_size - stuffed_bits];
|
||||
let mut index: i32 = 0;
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < num_data_codewords {
|
||||
{
|
||||
let data_word: i32 = data_words[i];
|
||||
if data_word == 1 || data_word == mask - 1 {
|
||||
// next codewordSize-1 bits are all zeros or all ones
|
||||
Arrays::fill(&corrected_bits, index, index + codeword_size - 1, data_word > 1);
|
||||
index += codeword_size - 1;
|
||||
} else {
|
||||
{
|
||||
let mut bit: i32 = codeword_size - 1;
|
||||
while bit >= 0 {
|
||||
{
|
||||
corrected_bits[index += 1 !!!check!!! post increment] = (data_word & (1 << bit)) != 0;
|
||||
}
|
||||
bit -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
return Ok(CorrectedBitsResult::new(&corrected_bits, 100 * (num_codewords - num_data_codewords) / num_codewords));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the array of bits from an Aztec Code matrix
|
||||
*
|
||||
* @return the array of bits
|
||||
*/
|
||||
fn extract_bits(&self, matrix: &BitMatrix) -> Vec<bool> {
|
||||
let compact: bool = self.ddata.is_compact();
|
||||
let layers: i32 = self.ddata.get_nb_layers();
|
||||
// not including alignment lines
|
||||
let base_matrix_size: i32 = ( if compact { 11 } else { 14 }) + layers * 4;
|
||||
let alignment_map: [i32; base_matrix_size] = [0; base_matrix_size];
|
||||
let mut rawbits: [bool; ::total_bits_in_layer(layers, compact)] = [false; ::total_bits_in_layer(layers, compact)];
|
||||
if compact {
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < alignment_map.len() {
|
||||
{
|
||||
alignment_map[i] = i;
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
let matrix_size: i32 = base_matrix_size + 1 + 2 * ((base_matrix_size / 2 - 1) / 15);
|
||||
let orig_center: i32 = base_matrix_size / 2;
|
||||
let center: i32 = matrix_size / 2;
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < orig_center {
|
||||
{
|
||||
let new_offset: i32 = i + i / 15;
|
||||
alignment_map[orig_center - i - 1] = center - new_offset - 1;
|
||||
alignment_map[orig_center + i] = center + new_offset + 1;
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
{
|
||||
let mut i: i32 = 0, let row_offset: i32 = 0;
|
||||
while i < layers {
|
||||
{
|
||||
let row_size: i32 = (layers - i) * 4 + ( if compact { 9 } else { 12 });
|
||||
// The top-left most point of this layer is <low, low> (not including alignment lines)
|
||||
let low: i32 = i * 2;
|
||||
// The bottom-right most point of this layer is <high, high> (not including alignment lines)
|
||||
let high: i32 = base_matrix_size - 1 - low;
|
||||
// We pull bits from the two 2 x rowSize columns and two rowSize x 2 rows
|
||||
{
|
||||
let mut j: i32 = 0;
|
||||
while j < row_size {
|
||||
{
|
||||
let column_offset: i32 = j * 2;
|
||||
{
|
||||
let mut k: i32 = 0;
|
||||
while k < 2 {
|
||||
{
|
||||
// left column
|
||||
rawbits[row_offset + column_offset + k] = matrix.get(alignment_map[low + k], alignment_map[low + j]);
|
||||
// bottom row
|
||||
rawbits[row_offset + 2 * row_size + column_offset + k] = matrix.get(alignment_map[low + j], alignment_map[high - k]);
|
||||
// right column
|
||||
rawbits[row_offset + 4 * row_size + column_offset + k] = matrix.get(alignment_map[high - k], alignment_map[high - j]);
|
||||
// top row
|
||||
rawbits[row_offset + 6 * row_size + column_offset + k] = matrix.get(alignment_map[high - j], alignment_map[low + k]);
|
||||
}
|
||||
k += 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
j += 1;
|
||||
}
|
||||
}
|
||||
|
||||
row_offset += row_size * 8;
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
return rawbits;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a code of given length and at given index in an array of bits
|
||||
*/
|
||||
fn read_code( rawbits: &Vec<bool>, start_index: i32, length: i32) -> i32 {
|
||||
let mut res: i32 = 0;
|
||||
{
|
||||
let mut i: i32 = start_index;
|
||||
while i < start_index + length {
|
||||
{
|
||||
res <<= 1;
|
||||
if rawbits[i] {
|
||||
res |= 0x01;
|
||||
}
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a code of length 8 in an array of bits, padding with zeros
|
||||
*/
|
||||
fn read_byte( rawbits: &Vec<bool>, start_index: i32) -> i8 {
|
||||
let n: i32 = rawbits.len() - start_index;
|
||||
if n >= 8 {
|
||||
return ::read_code(&rawbits, start_index, 8) as i8;
|
||||
}
|
||||
return (::read_code(&rawbits, start_index, n) << (8 - n)) as i8;
|
||||
}
|
||||
|
||||
/**
|
||||
* Packs a bit array into bytes, most significant bit first
|
||||
*/
|
||||
fn convert_bool_array_to_byte_array( bool_arr: &Vec<bool>) -> Vec<i8> {
|
||||
let byte_arr: [i8; (bool_arr.len() + 7) / 8] = [0; (bool_arr.len() + 7) / 8];
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < byte_arr.len() {
|
||||
{
|
||||
byte_arr[i] = ::read_byte(&bool_arr, 8 * i);
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
return byte_arr;
|
||||
}
|
||||
|
||||
fn total_bits_in_layer( layers: i32, compact: bool) -> i32 {
|
||||
return (( if compact { 88 } else { 112 }) + 16 * layers) * layers;
|
||||
}
|
||||
}
|
||||
|
||||
586
port_src/output/zxing/aztec/detector/detector.rs
Normal file
586
port_src/output/zxing/aztec/detector/detector.rs
Normal file
@@ -0,0 +1,586 @@
|
||||
/*
|
||||
* 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::aztec::detector;
|
||||
|
||||
/**
|
||||
* Encapsulates logic that can detect an Aztec Code in an image, even if the Aztec Code
|
||||
* is rotated or skewed, or partially obscured.
|
||||
*
|
||||
* @author David Olivier
|
||||
* @author Frank Yellin
|
||||
*/
|
||||
|
||||
const EXPECTED_CORNER_BITS: vec![Vec<i32>; 4] = vec![// 07340 XXX .XX X.. ...
|
||||
0xee0, // 00734 ... XXX .XX X..
|
||||
0x1dc, // 04073 X.. ... XXX .XX
|
||||
0x83b, // 03407 .XX X.. ... XXX
|
||||
0x707, ]
|
||||
;
|
||||
pub struct Detector {
|
||||
|
||||
let image: BitMatrix;
|
||||
|
||||
let mut compact: bool;
|
||||
|
||||
let nb_layers: i32;
|
||||
|
||||
let nb_data_blocks: i32;
|
||||
|
||||
let nb_center_layers: i32;
|
||||
|
||||
let mut shift: i32;
|
||||
}
|
||||
|
||||
impl Detector {
|
||||
|
||||
pub fn new( image: &BitMatrix) -> Detector {
|
||||
let .image = image;
|
||||
}
|
||||
|
||||
pub fn detect(&self) -> /* throws NotFoundException */Result<AztecDetectorResult, Rc<Exception>> {
|
||||
return Ok(self.detect(false));
|
||||
}
|
||||
|
||||
/**
|
||||
* Detects an Aztec Code in an image.
|
||||
*
|
||||
* @param isMirror if true, image is a mirror-image of original
|
||||
* @return {@link AztecDetectorResult} encapsulating results of detecting an Aztec Code
|
||||
* @throws NotFoundException if no Aztec Code can be found
|
||||
*/
|
||||
pub fn detect(&self, is_mirror: bool) -> /* throws NotFoundException */Result<AztecDetectorResult, Rc<Exception>> {
|
||||
// 1. Get the center of the aztec matrix
|
||||
let p_center: Point = self.get_matrix_center();
|
||||
// 2. Get the center points of the four diagonal points just outside the bull's eye
|
||||
// [topRight, bottomRight, bottomLeft, topLeft]
|
||||
let bulls_eye_corners: Vec<ResultPoint> = self.get_bulls_eye_corners(p_center);
|
||||
if is_mirror {
|
||||
let temp: ResultPoint = bulls_eye_corners[0];
|
||||
bulls_eye_corners[0] = bulls_eye_corners[2];
|
||||
bulls_eye_corners[2] = temp;
|
||||
}
|
||||
// 3. Get the size of the matrix and other parameters from the bull's eye
|
||||
self.extract_parameters(bulls_eye_corners);
|
||||
// 4. Sample the grid
|
||||
let bits: BitMatrix = self.sample_grid(self.image, bulls_eye_corners[self.shift % 4], bulls_eye_corners[(self.shift + 1) % 4], bulls_eye_corners[(self.shift + 2) % 4], bulls_eye_corners[(self.shift + 3) % 4]);
|
||||
// 5. Get the corners of the matrix.
|
||||
let corners: Vec<ResultPoint> = self.get_matrix_corner_points(bulls_eye_corners);
|
||||
return Ok(AztecDetectorResult::new(bits, corners, self.compact, self.nb_data_blocks, self.nb_layers));
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the number of data layers and data blocks from the layer around the bull's eye.
|
||||
*
|
||||
* @param bullsEyeCorners the array of bull's eye corners
|
||||
* @throws NotFoundException in case of too many errors or invalid parameters
|
||||
*/
|
||||
fn extract_parameters(&self, bulls_eye_corners: &Vec<ResultPoint>) -> /* throws NotFoundException */Result<Void, Rc<Exception>> {
|
||||
if !self.is_valid(bulls_eye_corners[0]) || !self.is_valid(bulls_eye_corners[1]) || !self.is_valid(bulls_eye_corners[2]) || !self.is_valid(bulls_eye_corners[3]) {
|
||||
throw NotFoundException::get_not_found_instance();
|
||||
}
|
||||
let length: i32 = 2 * self.nb_center_layers;
|
||||
// Get the bits around the bull's eye
|
||||
let sides: vec![Vec<i32>; 4] = vec![// Right side
|
||||
self.sample_line(bulls_eye_corners[0], bulls_eye_corners[1], length), // Bottom
|
||||
self.sample_line(bulls_eye_corners[1], bulls_eye_corners[2], length), // Left side
|
||||
self.sample_line(bulls_eye_corners[2], bulls_eye_corners[3], length), // Top
|
||||
self.sample_line(bulls_eye_corners[3], bulls_eye_corners[0], length), ]
|
||||
;
|
||||
// bullsEyeCorners[shift] is the corner of the bulls'eye that has three
|
||||
// orientation marks.
|
||||
// sides[shift] is the row/column that goes from the corner with three
|
||||
// orientation marks to the corner with two.
|
||||
self.shift = ::get_rotation(&sides, length);
|
||||
// Flatten the parameter bits into a single 28- or 40-bit long
|
||||
let parameter_data: i64 = 0;
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < 4 {
|
||||
{
|
||||
let side: i32 = sides[(self.shift + i) % 4];
|
||||
if self.compact {
|
||||
// Each side of the form ..XXXXXXX. where Xs are parameter data
|
||||
parameter_data <<= 7;
|
||||
parameter_data += (side >> 1) & 0x7F;
|
||||
} else {
|
||||
// Each side of the form ..XXXXX.XXXXX. where Xs are parameter data
|
||||
parameter_data <<= 10;
|
||||
parameter_data += ((side >> 2) & (0x1f << 5)) + ((side >> 1) & 0x1F);
|
||||
}
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Corrects parameter data using RS. Returns just the data portion
|
||||
// without the error correction.
|
||||
let corrected_data: i32 = ::get_corrected_parameter_data(parameter_data, self.compact);
|
||||
if self.compact {
|
||||
// 8 bits: 2 bits layers and 6 bits data blocks
|
||||
self.nb_layers = (corrected_data >> 6) + 1;
|
||||
self.nb_data_blocks = (corrected_data & 0x3F) + 1;
|
||||
} else {
|
||||
// 16 bits: 5 bits layers and 11 bits data blocks
|
||||
self.nb_layers = (corrected_data >> 11) + 1;
|
||||
self.nb_data_blocks = (corrected_data & 0x7FF) + 1;
|
||||
}
|
||||
}
|
||||
|
||||
fn get_rotation( sides: &Vec<i32>, length: i32) -> /* throws NotFoundException */Result<i32, Rc<Exception>> {
|
||||
// In a normal pattern, we expect to See
|
||||
// ** .* D A
|
||||
// * *
|
||||
//
|
||||
// . *
|
||||
// .. .. C B
|
||||
//
|
||||
// Grab the 3 bits from each of the sides the form the locator pattern and concatenate
|
||||
// into a 12-bit integer. Start with the bit at A
|
||||
let corner_bits: i32 = 0;
|
||||
for let side: i32 in sides {
|
||||
// XX......X where X's are orientation marks
|
||||
let t: i32 = ((side >> (length - 2)) << 1) + (side & 1);
|
||||
corner_bits = (corner_bits << 3) + t;
|
||||
}
|
||||
// Mov the bottom bit to the top, so that the three bits of the locator pattern at A are
|
||||
// together. cornerBits is now:
|
||||
// 3 orientation bits at A || 3 orientation bits at B || ... || 3 orientation bits at D
|
||||
corner_bits = ((corner_bits & 1) << 11) + (corner_bits >> 1);
|
||||
// can easily tolerate two errors.
|
||||
{
|
||||
let mut shift: i32 = 0;
|
||||
while shift < 4 {
|
||||
{
|
||||
if Integer::bit_count(corner_bits ^ EXPECTED_CORNER_BITS[shift]) <= 2 {
|
||||
return Ok(shift);
|
||||
}
|
||||
}
|
||||
shift += 1;
|
||||
}
|
||||
}
|
||||
|
||||
throw NotFoundException::get_not_found_instance();
|
||||
}
|
||||
|
||||
/**
|
||||
* Corrects the parameter bits using Reed-Solomon algorithm.
|
||||
*
|
||||
* @param parameterData parameter bits
|
||||
* @param compact true if this is a compact Aztec code
|
||||
* @throws NotFoundException if the array contains too many errors
|
||||
*/
|
||||
fn get_corrected_parameter_data( parameter_data: i64, compact: bool) -> /* throws NotFoundException */Result<i32, Rc<Exception>> {
|
||||
let num_codewords: i32;
|
||||
let num_data_codewords: i32;
|
||||
if compact {
|
||||
num_codewords = 7;
|
||||
num_data_codewords = 2;
|
||||
} else {
|
||||
num_codewords = 10;
|
||||
num_data_codewords = 4;
|
||||
}
|
||||
let num_e_c_codewords: i32 = num_codewords - num_data_codewords;
|
||||
let parameter_words: [i32; num_codewords] = [0; num_codewords];
|
||||
{
|
||||
let mut i: i32 = num_codewords - 1;
|
||||
while i >= 0 {
|
||||
{
|
||||
parameter_words[i] = parameter_data as i32 & 0xF;
|
||||
parameter_data >>= 4;
|
||||
}
|
||||
i -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
let tryResult1 = 0;
|
||||
'try1: loop {
|
||||
{
|
||||
let rs_decoder: ReedSolomonDecoder = ReedSolomonDecoder::new(GenericGF::AZTEC_PARAM);
|
||||
rs_decoder.decode(¶meter_words, num_e_c_codewords);
|
||||
}
|
||||
break 'try1
|
||||
}
|
||||
match tryResult1 {
|
||||
catch ( ignored: &ReedSolomonException) {
|
||||
throw NotFoundException::get_not_found_instance();
|
||||
} 0 => break
|
||||
}
|
||||
|
||||
// Toss the error correction. Just return the data as an integer
|
||||
let mut result: i32 = 0;
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < num_data_codewords {
|
||||
{
|
||||
result = (result << 4) + parameter_words[i];
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the corners of a bull-eye centered on the passed point.
|
||||
* This returns the centers of the diagonal points just outside the bull's eye
|
||||
* Returns [topRight, bottomRight, bottomLeft, topLeft]
|
||||
*
|
||||
* @param pCenter Center point
|
||||
* @return The corners of the bull-eye
|
||||
* @throws NotFoundException If no valid bull-eye can be found
|
||||
*/
|
||||
fn get_bulls_eye_corners(&self, p_center: &Point) -> /* throws NotFoundException */Result<Vec<ResultPoint>, Rc<Exception>> {
|
||||
let mut pina: Point = p_center;
|
||||
let mut pinb: Point = p_center;
|
||||
let mut pinc: Point = p_center;
|
||||
let mut pind: Point = p_center;
|
||||
let mut color: bool = true;
|
||||
{
|
||||
self.nb_center_layers = 1;
|
||||
while self.nb_center_layers < 9 {
|
||||
{
|
||||
let pouta: Point = self.get_first_different(pina, color, 1, -1);
|
||||
let poutb: Point = self.get_first_different(pinb, color, 1, 1);
|
||||
let poutc: Point = self.get_first_different(pinc, color, -1, 1);
|
||||
let poutd: Point = self.get_first_different(pind, color, -1, -1);
|
||||
if self.nb_center_layers > 2 {
|
||||
let q: f32 = ::distance(poutd, pouta) * self.nb_center_layers / (::distance(pind, pina) * (self.nb_center_layers + 2));
|
||||
if q < 0.75 || q > 1.25 || !self.is_white_or_black_rectangle(pouta, poutb, poutc, poutd) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
pina = pouta;
|
||||
pinb = poutb;
|
||||
pinc = poutc;
|
||||
pind = poutd;
|
||||
color = !color;
|
||||
}
|
||||
self.nb_center_layers += 1;
|
||||
}
|
||||
}
|
||||
|
||||
if self.nb_center_layers != 5 && self.nb_center_layers != 7 {
|
||||
throw NotFoundException::get_not_found_instance();
|
||||
}
|
||||
self.compact = self.nb_center_layers == 5;
|
||||
// Expand the square by .5 pixel in each direction so that we're on the border
|
||||
// between the white square and the black square
|
||||
let pinax: ResultPoint = ResultPoint::new(pina.get_x() + 0.5f, pina.get_y() - 0.5f);
|
||||
let pinbx: ResultPoint = ResultPoint::new(pinb.get_x() + 0.5f, pinb.get_y() + 0.5f);
|
||||
let pincx: ResultPoint = ResultPoint::new(pinc.get_x() - 0.5f, pinc.get_y() + 0.5f);
|
||||
let pindx: ResultPoint = ResultPoint::new(pind.get_x() - 0.5f, pind.get_y() - 0.5f);
|
||||
// just outside the bull's eye.
|
||||
return Ok(::expand_square( : vec![ResultPoint; 4] = vec![pinax, pinbx, pincx, pindx, ]
|
||||
, 2 * self.nb_center_layers - 3, 2 * self.nb_center_layers));
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds a candidate center point of an Aztec code from an image
|
||||
*
|
||||
* @return the center point
|
||||
*/
|
||||
fn get_matrix_center(&self) -> Point {
|
||||
let point_a: ResultPoint;
|
||||
let point_b: ResultPoint;
|
||||
let point_c: ResultPoint;
|
||||
let point_d: ResultPoint;
|
||||
//Get a white rectangle that can be the border of the matrix in center bull's eye or
|
||||
let tryResult1 = 0;
|
||||
'try1: loop {
|
||||
{
|
||||
let corner_points: Vec<ResultPoint> = WhiteRectangleDetector::new(self.image).detect();
|
||||
point_a = corner_points[0];
|
||||
point_b = corner_points[1];
|
||||
point_c = corner_points[2];
|
||||
point_d = corner_points[3];
|
||||
}
|
||||
break 'try1
|
||||
}
|
||||
match tryResult1 {
|
||||
catch ( e: &NotFoundException) {
|
||||
let cx: i32 = self.image.get_width() / 2;
|
||||
let cy: i32 = self.image.get_height() / 2;
|
||||
point_a = self.get_first_different(Point::new(cx + 7, cy - 7), false, 1, -1).to_result_point();
|
||||
point_b = self.get_first_different(Point::new(cx + 7, cy + 7), false, 1, 1).to_result_point();
|
||||
point_c = self.get_first_different(Point::new(cx - 7, cy + 7), false, -1, 1).to_result_point();
|
||||
point_d = self.get_first_different(Point::new(cx - 7, cy - 7), false, -1, -1).to_result_point();
|
||||
} 0 => break
|
||||
}
|
||||
|
||||
//Compute the center of the rectangle
|
||||
let mut cx: i32 = MathUtils::round((point_a.get_x() + point_d.get_x() + point_b.get_x() + point_c.get_x()) / 4.0f);
|
||||
let mut cy: i32 = MathUtils::round((point_a.get_y() + point_d.get_y() + point_b.get_y() + point_c.get_y()) / 4.0f);
|
||||
// in order to compute a more accurate center.
|
||||
let tryResult1 = 0;
|
||||
'try1: loop {
|
||||
{
|
||||
let corner_points: Vec<ResultPoint> = WhiteRectangleDetector::new(self.image, 15, cx, cy).detect();
|
||||
point_a = corner_points[0];
|
||||
point_b = corner_points[1];
|
||||
point_c = corner_points[2];
|
||||
point_d = corner_points[3];
|
||||
}
|
||||
break 'try1
|
||||
}
|
||||
match tryResult1 {
|
||||
catch ( e: &NotFoundException) {
|
||||
point_a = self.get_first_different(Point::new(cx + 7, cy - 7), false, 1, -1).to_result_point();
|
||||
point_b = self.get_first_different(Point::new(cx + 7, cy + 7), false, 1, 1).to_result_point();
|
||||
point_c = self.get_first_different(Point::new(cx - 7, cy + 7), false, -1, 1).to_result_point();
|
||||
point_d = self.get_first_different(Point::new(cx - 7, cy - 7), false, -1, -1).to_result_point();
|
||||
} 0 => break
|
||||
}
|
||||
|
||||
// Recompute the center of the rectangle
|
||||
cx = MathUtils::round((point_a.get_x() + point_d.get_x() + point_b.get_x() + point_c.get_x()) / 4.0f);
|
||||
cy = MathUtils::round((point_a.get_y() + point_d.get_y() + point_b.get_y() + point_c.get_y()) / 4.0f);
|
||||
return Point::new(cx, cy);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the Aztec code corners from the bull's eye corners and the parameters.
|
||||
*
|
||||
* @param bullsEyeCorners the array of bull's eye corners
|
||||
* @return the array of aztec code corners
|
||||
*/
|
||||
fn get_matrix_corner_points(&self, bulls_eye_corners: &Vec<ResultPoint>) -> Vec<ResultPoint> {
|
||||
return ::expand_square(bulls_eye_corners, 2 * self.nb_center_layers, &self.get_dimension());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a BitMatrix by sampling the provided image.
|
||||
* topLeft, topRight, bottomRight, and bottomLeft are the centers of the squares on the
|
||||
* diagonal just outside the bull's eye.
|
||||
*/
|
||||
fn sample_grid(&self, image: &BitMatrix, top_left: &ResultPoint, top_right: &ResultPoint, bottom_right: &ResultPoint, bottom_left: &ResultPoint) -> /* throws NotFoundException */Result<BitMatrix, Rc<Exception>> {
|
||||
let sampler: GridSampler = GridSampler::get_instance();
|
||||
let dimension: i32 = self.get_dimension();
|
||||
let low: f32 = dimension / 2.0f - self.nb_center_layers;
|
||||
let high: f32 = dimension / 2.0f + self.nb_center_layers;
|
||||
return Ok(sampler.sample_grid(image, dimension, dimension, // topleft
|
||||
low, // topleft
|
||||
low, // topright
|
||||
high, // topright
|
||||
low, // bottomright
|
||||
high, // bottomright
|
||||
high, // bottomleft
|
||||
low, // bottomleft
|
||||
high, &top_left.get_x(), &top_left.get_y(), &top_right.get_x(), &top_right.get_y(), &bottom_right.get_x(), &bottom_right.get_y(), &bottom_left.get_x(), &bottom_left.get_y()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Samples a line.
|
||||
*
|
||||
* @param p1 start point (inclusive)
|
||||
* @param p2 end point (exclusive)
|
||||
* @param size number of bits
|
||||
* @return the array of bits as an int (first bit is high-order bit of result)
|
||||
*/
|
||||
fn sample_line(&self, p1: &ResultPoint, p2: &ResultPoint, size: i32) -> i32 {
|
||||
let mut result: i32 = 0;
|
||||
let d: f32 = ::distance(p1, p2);
|
||||
let module_size: f32 = d / size;
|
||||
let px: f32 = p1.get_x();
|
||||
let py: f32 = p1.get_y();
|
||||
let dx: f32 = module_size * (p2.get_x() - p1.get_x()) / d;
|
||||
let dy: f32 = module_size * (p2.get_y() - p1.get_y()) / d;
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < size {
|
||||
{
|
||||
if self.image.get(&MathUtils::round(px + i * dx), &MathUtils::round(py + i * dy)) {
|
||||
result |= 1 << (size - i - 1);
|
||||
}
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if the border of the rectangle passed in parameter is compound of white points only
|
||||
* or black points only
|
||||
*/
|
||||
fn is_white_or_black_rectangle(&self, p1: &Point, p2: &Point, p3: &Point, p4: &Point) -> bool {
|
||||
let corr: i32 = 3;
|
||||
p1 = Point::new(&Math::max(0, p1.get_x() - corr), &Math::min(self.image.get_height() - 1, p1.get_y() + corr));
|
||||
p2 = Point::new(&Math::max(0, p2.get_x() - corr), &Math::max(0, p2.get_y() - corr));
|
||||
p3 = Point::new(&Math::min(self.image.get_width() - 1, p3.get_x() + corr), &Math::max(0, &Math::min(self.image.get_height() - 1, p3.get_y() - corr)));
|
||||
p4 = Point::new(&Math::min(self.image.get_width() - 1, p4.get_x() + corr), &Math::min(self.image.get_height() - 1, p4.get_y() + corr));
|
||||
let c_init: i32 = self.get_color(p4, p1);
|
||||
if c_init == 0 {
|
||||
return false;
|
||||
}
|
||||
let mut c: i32 = self.get_color(p1, p2);
|
||||
if c != c_init {
|
||||
return false;
|
||||
}
|
||||
c = self.get_color(p2, p3);
|
||||
if c != c_init {
|
||||
return false;
|
||||
}
|
||||
c = self.get_color(p3, p4);
|
||||
return c == c_init;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the color of a segment
|
||||
*
|
||||
* @return 1 if segment more than 90% black, -1 if segment is more than 90% white, 0 else
|
||||
*/
|
||||
fn get_color(&self, p1: &Point, p2: &Point) -> i32 {
|
||||
let d: f32 = ::distance(p1, p2);
|
||||
if d == 0.0f {
|
||||
return 0;
|
||||
}
|
||||
let dx: f32 = (p2.get_x() - p1.get_x()) / d;
|
||||
let dy: f32 = (p2.get_y() - p1.get_y()) / d;
|
||||
let mut error: i32 = 0;
|
||||
let mut px: f32 = p1.get_x();
|
||||
let mut py: f32 = p1.get_y();
|
||||
let color_model: bool = self.image.get(&p1.get_x(), &p1.get_y());
|
||||
let i_max: i32 = Math::floor(d) as i32;
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < i_max {
|
||||
{
|
||||
if self.image.get(&MathUtils::round(px), &MathUtils::round(py)) != color_model {
|
||||
error += 1;
|
||||
}
|
||||
px += dx;
|
||||
py += dy;
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
let err_ratio: f32 = error / d;
|
||||
if err_ratio > 0.1f && err_ratio < 0.9f {
|
||||
return 0;
|
||||
}
|
||||
return if (err_ratio <= 0.1f) == color_model { 1 } else { -1 };
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the coordinate of the first point with a different color in the given direction
|
||||
*/
|
||||
fn get_first_different(&self, init: &Point, color: bool, dx: i32, dy: i32) -> Point {
|
||||
let mut x: i32 = init.get_x() + dx;
|
||||
let mut y: i32 = init.get_y() + dy;
|
||||
while self.is_valid(x, y) && self.image.get(x, y) == color {
|
||||
x += dx;
|
||||
y += dy;
|
||||
}
|
||||
x -= dx;
|
||||
y -= dy;
|
||||
while self.is_valid(x, y) && self.image.get(x, y) == color {
|
||||
x += dx;
|
||||
}
|
||||
x -= dx;
|
||||
while self.is_valid(x, y) && self.image.get(x, y) == color {
|
||||
y += dy;
|
||||
}
|
||||
y -= dy;
|
||||
return Point::new(x, y);
|
||||
}
|
||||
|
||||
/**
|
||||
* Expand the square represented by the corner points by pushing out equally in all directions
|
||||
*
|
||||
* @param cornerPoints the corners of the square, which has the bull's eye at its center
|
||||
* @param oldSide the original length of the side of the square in the target bit matrix
|
||||
* @param newSide the new length of the size of the square in the target bit matrix
|
||||
* @return the corners of the expanded square
|
||||
*/
|
||||
fn expand_square( corner_points: &Vec<ResultPoint>, old_side: i32, new_side: i32) -> Vec<ResultPoint> {
|
||||
let ratio: f32 = new_side / (2.0f * old_side);
|
||||
let mut dx: f32 = corner_points[0].get_x() - corner_points[2].get_x();
|
||||
let mut dy: f32 = corner_points[0].get_y() - corner_points[2].get_y();
|
||||
let mut centerx: f32 = (corner_points[0].get_x() + corner_points[2].get_x()) / 2.0f;
|
||||
let mut centery: f32 = (corner_points[0].get_y() + corner_points[2].get_y()) / 2.0f;
|
||||
let result0: ResultPoint = ResultPoint::new(centerx + ratio * dx, centery + ratio * dy);
|
||||
let result2: ResultPoint = ResultPoint::new(centerx - ratio * dx, centery - ratio * dy);
|
||||
dx = corner_points[1].get_x() - corner_points[3].get_x();
|
||||
dy = corner_points[1].get_y() - corner_points[3].get_y();
|
||||
centerx = (corner_points[1].get_x() + corner_points[3].get_x()) / 2.0f;
|
||||
centery = (corner_points[1].get_y() + corner_points[3].get_y()) / 2.0f;
|
||||
let result1: ResultPoint = ResultPoint::new(centerx + ratio * dx, centery + ratio * dy);
|
||||
let result3: ResultPoint = ResultPoint::new(centerx - ratio * dx, centery - ratio * dy);
|
||||
return : vec![ResultPoint; 4] = vec![result0, result1, result2, result3, ]
|
||||
;
|
||||
}
|
||||
|
||||
fn is_valid(&self, x: i32, y: i32) -> bool {
|
||||
return x >= 0 && x < self.image.get_width() && y >= 0 && y < self.image.get_height();
|
||||
}
|
||||
|
||||
fn is_valid(&self, point: &ResultPoint) -> bool {
|
||||
let x: i32 = MathUtils::round(&point.get_x());
|
||||
let y: i32 = MathUtils::round(&point.get_y());
|
||||
return self.is_valid(x, y);
|
||||
}
|
||||
|
||||
fn distance( a: &Point, b: &Point) -> f32 {
|
||||
return MathUtils::distance(&a.get_x(), &a.get_y(), &b.get_x(), &b.get_y());
|
||||
}
|
||||
|
||||
fn distance( a: &ResultPoint, b: &ResultPoint) -> f32 {
|
||||
return MathUtils::distance(&a.get_x(), &a.get_y(), &b.get_x(), &b.get_y());
|
||||
}
|
||||
|
||||
fn get_dimension(&self) -> i32 {
|
||||
if self.compact {
|
||||
return 4 * self.nb_layers + 11;
|
||||
}
|
||||
return 4 * self.nb_layers + 2 * ((2 * self.nb_layers + 6) / 15) + 15;
|
||||
}
|
||||
|
||||
struct Point {
|
||||
|
||||
let x: i32;
|
||||
|
||||
let y: i32;
|
||||
}
|
||||
|
||||
impl Point {
|
||||
|
||||
fn to_result_point(&self) -> ResultPoint {
|
||||
return ResultPoint::new(self.x, self.y);
|
||||
}
|
||||
|
||||
fn new( x: i32, y: i32) -> Point {
|
||||
let .x = x;
|
||||
let .y = y;
|
||||
}
|
||||
|
||||
fn get_x(&self) -> i32 {
|
||||
return self.x;
|
||||
}
|
||||
|
||||
fn get_y(&self) -> i32 {
|
||||
return self.y;
|
||||
}
|
||||
|
||||
pub fn to_string(&self) -> String {
|
||||
return format!("<{} {}>", self.x, self.y);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
93
port_src/output/zxing/aztec/encoder/aztec_code.rs
Normal file
93
port_src/output/zxing/aztec/encoder/aztec_code.rs
Normal file
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* 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::aztec::encoder;
|
||||
|
||||
/**
|
||||
* Aztec 2D code representation
|
||||
*
|
||||
* @author Rustam Abdullaev
|
||||
*/
|
||||
pub struct AztecCode {
|
||||
|
||||
let compact: bool;
|
||||
|
||||
let size: i32;
|
||||
|
||||
let layers: i32;
|
||||
|
||||
let code_words: i32;
|
||||
|
||||
let matrix: BitMatrix;
|
||||
}
|
||||
|
||||
impl AztecCode {
|
||||
|
||||
/**
|
||||
* @return {@code true} if compact instead of full mode
|
||||
*/
|
||||
pub fn is_compact(&self) -> bool {
|
||||
return self.compact;
|
||||
}
|
||||
|
||||
pub fn set_compact(&self, compact: bool) {
|
||||
self.compact = compact;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return size in pixels (width and height)
|
||||
*/
|
||||
pub fn get_size(&self) -> i32 {
|
||||
return self.size;
|
||||
}
|
||||
|
||||
pub fn set_size(&self, size: i32) {
|
||||
self.size = size;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return number of levels
|
||||
*/
|
||||
pub fn get_layers(&self) -> i32 {
|
||||
return self.layers;
|
||||
}
|
||||
|
||||
pub fn set_layers(&self, layers: i32) {
|
||||
self.layers = layers;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return number of data codewords
|
||||
*/
|
||||
pub fn get_code_words(&self) -> i32 {
|
||||
return self.code_words;
|
||||
}
|
||||
|
||||
pub fn set_code_words(&self, code_words: i32) {
|
||||
self.codeWords = code_words;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the symbol image
|
||||
*/
|
||||
pub fn get_matrix(&self) -> BitMatrix {
|
||||
return self.matrix;
|
||||
}
|
||||
|
||||
pub fn set_matrix(&self, matrix: &BitMatrix) {
|
||||
self.matrix = matrix;
|
||||
}
|
||||
}
|
||||
|
||||
67
port_src/output/zxing/aztec/encoder/binary_shift_token.rs
Normal file
67
port_src/output/zxing/aztec/encoder/binary_shift_token.rs
Normal file
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* 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::aztec::encoder;
|
||||
|
||||
struct BinaryShiftToken {
|
||||
super: Token;
|
||||
|
||||
let binary_shift_start: i32;
|
||||
|
||||
let binary_shift_byte_count: i32;
|
||||
}
|
||||
|
||||
impl BinaryShiftToken {
|
||||
|
||||
fn new( previous: &Token, binary_shift_start: i32, binary_shift_byte_count: i32) -> BinaryShiftToken {
|
||||
super(previous);
|
||||
let .binaryShiftStart = binary_shift_start;
|
||||
let .binaryShiftByteCount = binary_shift_byte_count;
|
||||
}
|
||||
|
||||
pub fn append_to(&self, bit_array: &BitArray, text: &Vec<i8>) {
|
||||
let bsbc: i32 = self.binary_shift_byte_count;
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < bsbc {
|
||||
{
|
||||
if i == 0 || (i == 31 && bsbc <= 62) {
|
||||
// We need a header before the first character, and before
|
||||
// character 31 when the total byte code is <= 62
|
||||
// BINARY_SHIFT
|
||||
bit_array.append_bits(31, 5);
|
||||
if bsbc > 62 {
|
||||
bit_array.append_bits(bsbc - 31, 16);
|
||||
} else if i == 0 {
|
||||
// 1 <= binaryShiftByteCode <= 62
|
||||
bit_array.append_bits(&Math::min(bsbc, 31), 5);
|
||||
} else {
|
||||
// 32 <= binaryShiftCount <= 62 and i == 31
|
||||
bit_array.append_bits(bsbc - 31, 5);
|
||||
}
|
||||
}
|
||||
bit_array.append_bits(text[self.binary_shift_start + i], 8);
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
pub fn to_string(&self) -> String {
|
||||
return format!("<{}::{}>", self.binary_shift_start, (self.binary_shift_start + self.binary_shift_byte_count - 1));
|
||||
}
|
||||
}
|
||||
|
||||
516
port_src/output/zxing/aztec/encoder/encoder.rs
Normal file
516
port_src/output/zxing/aztec/encoder/encoder.rs
Normal file
@@ -0,0 +1,516 @@
|
||||
/*
|
||||
* 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::aztec::encoder;
|
||||
|
||||
/**
|
||||
* Generates Aztec 2D barcodes.
|
||||
*
|
||||
* @author Rustam Abdullaev
|
||||
*/
|
||||
|
||||
// default minimal percentage of error check words
|
||||
const DEFAULT_EC_PERCENT: i32 = 33;
|
||||
|
||||
const DEFAULT_AZTEC_LAYERS: i32 = 0;
|
||||
|
||||
const MAX_NB_BITS: i32 = 32;
|
||||
|
||||
const MAX_NB_BITS_COMPACT: i32 = 4;
|
||||
|
||||
const WORD_SIZE: vec![Vec<i32>; 33] = vec![4, 6, 6, 8, 8, 8, 8, 8, 8, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, ]
|
||||
;
|
||||
pub struct Encoder {
|
||||
}
|
||||
|
||||
impl Encoder {
|
||||
|
||||
fn new() -> Encoder {
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes the given string content as an Aztec symbol (without ECI code)
|
||||
*
|
||||
* @param data input data string; must be encodable as ISO/IEC 8859-1 (Latin-1)
|
||||
* @return Aztec symbol matrix with metadata
|
||||
*/
|
||||
pub fn encode( data: &String) -> AztecCode {
|
||||
return ::encode(&data.get_bytes(StandardCharsets::ISO_8859_1));
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes the given string content as an Aztec symbol (without ECI code)
|
||||
*
|
||||
* @param data input data string; must be encodable as ISO/IEC 8859-1 (Latin-1)
|
||||
* @param minECCPercent minimal percentage of error check words (According to ISO/IEC 24778:2008,
|
||||
* a minimum of 23% + 3 words is recommended)
|
||||
* @param userSpecifiedLayers if non-zero, a user-specified value for the number of layers
|
||||
* @return Aztec symbol matrix with metadata
|
||||
*/
|
||||
pub fn encode( data: &String, min_e_c_c_percent: i32, user_specified_layers: i32) -> AztecCode {
|
||||
return ::encode(&data.get_bytes(StandardCharsets::ISO_8859_1), min_e_c_c_percent, user_specified_layers, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes the given string content as an Aztec symbol
|
||||
*
|
||||
* @param data input data string
|
||||
* @param minECCPercent minimal percentage of error check words (According to ISO/IEC 24778:2008,
|
||||
* a minimum of 23% + 3 words is recommended)
|
||||
* @param userSpecifiedLayers if non-zero, a user-specified value for the number of layers
|
||||
* @param charset character set in which to encode string using ECI; if null, no ECI code
|
||||
* will be inserted, and the string must be encodable as ISO/IEC 8859-1
|
||||
* (Latin-1), the default encoding of the symbol.
|
||||
* @return Aztec symbol matrix with metadata
|
||||
*/
|
||||
pub fn encode( data: &String, min_e_c_c_percent: i32, user_specified_layers: i32, charset: &Charset) -> AztecCode {
|
||||
let bytes: Vec<i8> = data.get_bytes( if null != charset { charset } else { StandardCharsets::ISO_8859_1 });
|
||||
return ::encode(&bytes, min_e_c_c_percent, user_specified_layers, &charset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes the given binary content as an Aztec symbol (without ECI code)
|
||||
*
|
||||
* @param data input data string
|
||||
* @return Aztec symbol matrix with metadata
|
||||
*/
|
||||
pub fn encode( data: &Vec<i8>) -> AztecCode {
|
||||
return ::encode(&data, DEFAULT_EC_PERCENT, DEFAULT_AZTEC_LAYERS, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes the given binary content as an Aztec symbol (without ECI code)
|
||||
*
|
||||
* @param data input data string
|
||||
* @param minECCPercent minimal percentage of error check words (According to ISO/IEC 24778:2008,
|
||||
* a minimum of 23% + 3 words is recommended)
|
||||
* @param userSpecifiedLayers if non-zero, a user-specified value for the number of layers
|
||||
* @return Aztec symbol matrix with metadata
|
||||
*/
|
||||
pub fn encode( data: &Vec<i8>, min_e_c_c_percent: i32, user_specified_layers: i32) -> AztecCode {
|
||||
return ::encode(&data, min_e_c_c_percent, user_specified_layers, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes the given binary content as an Aztec symbol
|
||||
*
|
||||
* @param data input data string
|
||||
* @param minECCPercent minimal percentage of error check words (According to ISO/IEC 24778:2008,
|
||||
* a minimum of 23% + 3 words is recommended)
|
||||
* @param userSpecifiedLayers if non-zero, a user-specified value for the number of layers
|
||||
* @param charset character set to mark using ECI; if null, no ECI code will be inserted, and the
|
||||
* default encoding of ISO/IEC 8859-1 will be assuming by readers.
|
||||
* @return Aztec symbol matrix with metadata
|
||||
*/
|
||||
pub fn encode( data: &Vec<i8>, min_e_c_c_percent: i32, user_specified_layers: i32, charset: &Charset) -> AztecCode {
|
||||
// High-level encode
|
||||
let bits: BitArray = HighLevelEncoder::new(&data, &charset).encode();
|
||||
// stuff bits and choose symbol size
|
||||
let ecc_bits: i32 = bits.get_size() * min_e_c_c_percent / 100 + 11;
|
||||
let total_size_bits: i32 = bits.get_size() + ecc_bits;
|
||||
let mut compact: bool;
|
||||
let mut layers: i32;
|
||||
let total_bits_in_layer: i32;
|
||||
let word_size: i32;
|
||||
let stuffed_bits: BitArray;
|
||||
if user_specified_layers != DEFAULT_AZTEC_LAYERS {
|
||||
compact = user_specified_layers < 0;
|
||||
layers = Math::abs(user_specified_layers);
|
||||
if layers > ( if compact { MAX_NB_BITS_COMPACT } else { MAX_NB_BITS }) {
|
||||
throw IllegalArgumentException::new(&String::format("Illegal value %s for layers", user_specified_layers));
|
||||
}
|
||||
total_bits_in_layer = self.total_bits_in_layer(layers, compact);
|
||||
word_size = WORD_SIZE[layers];
|
||||
let usable_bits_in_layers: i32 = total_bits_in_layer - (total_bits_in_layer % word_size);
|
||||
stuffed_bits = ::stuff_bits(bits, word_size);
|
||||
if stuffed_bits.get_size() + ecc_bits > usable_bits_in_layers {
|
||||
throw IllegalArgumentException::new("Data to large for user specified layer");
|
||||
}
|
||||
if compact && stuffed_bits.get_size() > word_size * 64 {
|
||||
// Compact format only allows 64 data words, though C4 can hold more words than that
|
||||
throw IllegalArgumentException::new("Data to large for user specified layer");
|
||||
}
|
||||
} else {
|
||||
word_size = 0;
|
||||
stuffed_bits = null;
|
||||
// is the same size, but has more data.
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
loop {
|
||||
{
|
||||
if i > MAX_NB_BITS {
|
||||
throw IllegalArgumentException::new("Data too large for an Aztec code");
|
||||
}
|
||||
compact = i <= 3;
|
||||
layers = if compact { i + 1 } else { i };
|
||||
total_bits_in_layer = self.total_bits_in_layer(layers, compact);
|
||||
if total_size_bits > total_bits_in_layer {
|
||||
continue;
|
||||
}
|
||||
// wordSize has changed
|
||||
if stuffed_bits == null || word_size != WORD_SIZE[layers] {
|
||||
word_size = WORD_SIZE[layers];
|
||||
stuffed_bits = ::stuff_bits(bits, word_size);
|
||||
}
|
||||
let usable_bits_in_layers: i32 = total_bits_in_layer - (total_bits_in_layer % word_size);
|
||||
if compact && stuffed_bits.get_size() > word_size * 64 {
|
||||
// Compact format only allows 64 data words, though C4 can hold more words than that
|
||||
continue;
|
||||
}
|
||||
if stuffed_bits.get_size() + ecc_bits <= usable_bits_in_layers {
|
||||
break;
|
||||
}
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
let message_bits: BitArray = ::generate_check_words(stuffed_bits, total_bits_in_layer, word_size);
|
||||
// generate mode message
|
||||
let message_size_in_words: i32 = stuffed_bits.get_size() / word_size;
|
||||
let mode_message: BitArray = ::generate_mode_message(compact, layers, message_size_in_words);
|
||||
// allocate symbol
|
||||
// not including alignment lines
|
||||
let base_matrix_size: i32 = ( if compact { 11 } else { 14 }) + layers * 4;
|
||||
let alignment_map: [i32; base_matrix_size] = [0; base_matrix_size];
|
||||
let matrix_size: i32;
|
||||
if compact {
|
||||
// no alignment marks in compact mode, alignmentMap is a no-op
|
||||
matrix_size = base_matrix_size;
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < alignment_map.len() {
|
||||
{
|
||||
alignment_map[i] = i;
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
matrix_size = base_matrix_size + 1 + 2 * ((base_matrix_size / 2 - 1) / 15);
|
||||
let orig_center: i32 = base_matrix_size / 2;
|
||||
let center: i32 = matrix_size / 2;
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < orig_center {
|
||||
{
|
||||
let new_offset: i32 = i + i / 15;
|
||||
alignment_map[orig_center - i - 1] = center - new_offset - 1;
|
||||
alignment_map[orig_center + i] = center + new_offset + 1;
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
let matrix: BitMatrix = BitMatrix::new(matrix_size);
|
||||
// draw data bits
|
||||
{
|
||||
let mut i: i32 = 0, let row_offset: i32 = 0;
|
||||
while i < layers {
|
||||
{
|
||||
let row_size: i32 = (layers - i) * 4 + ( if compact { 9 } else { 12 });
|
||||
{
|
||||
let mut j: i32 = 0;
|
||||
while j < row_size {
|
||||
{
|
||||
let column_offset: i32 = j * 2;
|
||||
{
|
||||
let mut k: i32 = 0;
|
||||
while k < 2 {
|
||||
{
|
||||
if message_bits.get(row_offset + column_offset + k) {
|
||||
matrix.set(alignment_map[i * 2 + k], alignment_map[i * 2 + j]);
|
||||
}
|
||||
if message_bits.get(row_offset + row_size * 2 + column_offset + k) {
|
||||
matrix.set(alignment_map[i * 2 + j], alignment_map[base_matrix_size - 1 - i * 2 - k]);
|
||||
}
|
||||
if message_bits.get(row_offset + row_size * 4 + column_offset + k) {
|
||||
matrix.set(alignment_map[base_matrix_size - 1 - i * 2 - k], alignment_map[base_matrix_size - 1 - i * 2 - j]);
|
||||
}
|
||||
if message_bits.get(row_offset + row_size * 6 + column_offset + k) {
|
||||
matrix.set(alignment_map[base_matrix_size - 1 - i * 2 - j], alignment_map[i * 2 + k]);
|
||||
}
|
||||
}
|
||||
k += 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
j += 1;
|
||||
}
|
||||
}
|
||||
|
||||
row_offset += row_size * 8;
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
// draw mode message
|
||||
::draw_mode_message(matrix, compact, matrix_size, mode_message);
|
||||
// draw alignment marks
|
||||
if compact {
|
||||
::draw_bulls_eye(matrix, matrix_size / 2, 5);
|
||||
} else {
|
||||
::draw_bulls_eye(matrix, matrix_size / 2, 7);
|
||||
{
|
||||
let mut i: i32 = 0, let mut j: i32 = 0;
|
||||
while i < base_matrix_size / 2 - 1 {
|
||||
{
|
||||
{
|
||||
let mut k: i32 = (matrix_size / 2) & 1;
|
||||
while k < matrix_size {
|
||||
{
|
||||
matrix.set(matrix_size / 2 - j, k);
|
||||
matrix.set(matrix_size / 2 + j, k);
|
||||
matrix.set(k, matrix_size / 2 - j);
|
||||
matrix.set(k, matrix_size / 2 + j);
|
||||
}
|
||||
k += 2;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
i += 15;
|
||||
j += 16;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
let aztec: AztecCode = AztecCode::new();
|
||||
aztec.set_compact(compact);
|
||||
aztec.set_size(matrix_size);
|
||||
aztec.set_layers(layers);
|
||||
aztec.set_code_words(message_size_in_words);
|
||||
aztec.set_matrix(matrix);
|
||||
return aztec;
|
||||
}
|
||||
|
||||
fn draw_bulls_eye( matrix: &BitMatrix, center: i32, size: i32) {
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < size {
|
||||
{
|
||||
{
|
||||
let mut j: i32 = center - i;
|
||||
while j <= center + i {
|
||||
{
|
||||
matrix.set(j, center - i);
|
||||
matrix.set(j, center + i);
|
||||
matrix.set(center - i, j);
|
||||
matrix.set(center + i, j);
|
||||
}
|
||||
j += 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
i += 2;
|
||||
}
|
||||
}
|
||||
|
||||
matrix.set(center - size, center - size);
|
||||
matrix.set(center - size + 1, center - size);
|
||||
matrix.set(center - size, center - size + 1);
|
||||
matrix.set(center + size, center - size);
|
||||
matrix.set(center + size, center - size + 1);
|
||||
matrix.set(center + size, center + size - 1);
|
||||
}
|
||||
|
||||
fn generate_mode_message( compact: bool, layers: i32, message_size_in_words: i32) -> BitArray {
|
||||
let mode_message: BitArray = BitArray::new();
|
||||
if compact {
|
||||
mode_message.append_bits(layers - 1, 2);
|
||||
mode_message.append_bits(message_size_in_words - 1, 6);
|
||||
mode_message = ::generate_check_words(mode_message, 28, 4);
|
||||
} else {
|
||||
mode_message.append_bits(layers - 1, 5);
|
||||
mode_message.append_bits(message_size_in_words - 1, 11);
|
||||
mode_message = ::generate_check_words(mode_message, 40, 4);
|
||||
}
|
||||
return mode_message;
|
||||
}
|
||||
|
||||
fn draw_mode_message( matrix: &BitMatrix, compact: bool, matrix_size: i32, mode_message: &BitArray) {
|
||||
let center: i32 = matrix_size / 2;
|
||||
if compact {
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < 7 {
|
||||
{
|
||||
let offset: i32 = center - 3 + i;
|
||||
if mode_message.get(i) {
|
||||
matrix.set(offset, center - 5);
|
||||
}
|
||||
if mode_message.get(i + 7) {
|
||||
matrix.set(center + 5, offset);
|
||||
}
|
||||
if mode_message.get(20 - i) {
|
||||
matrix.set(offset, center + 5);
|
||||
}
|
||||
if mode_message.get(27 - i) {
|
||||
matrix.set(center - 5, offset);
|
||||
}
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < 10 {
|
||||
{
|
||||
let offset: i32 = center - 5 + i + i / 5;
|
||||
if mode_message.get(i) {
|
||||
matrix.set(offset, center - 7);
|
||||
}
|
||||
if mode_message.get(i + 10) {
|
||||
matrix.set(center + 7, offset);
|
||||
}
|
||||
if mode_message.get(29 - i) {
|
||||
matrix.set(offset, center + 7);
|
||||
}
|
||||
if mode_message.get(39 - i) {
|
||||
matrix.set(center - 7, offset);
|
||||
}
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
fn generate_check_words( bit_array: &BitArray, total_bits: i32, word_size: i32) -> BitArray {
|
||||
// bitArray is guaranteed to be a multiple of the wordSize, so no padding needed
|
||||
let message_size_in_words: i32 = bit_array.get_size() / word_size;
|
||||
let rs: ReedSolomonEncoder = ReedSolomonEncoder::new(&::get_g_f(word_size));
|
||||
let total_words: i32 = total_bits / word_size;
|
||||
let message_words: Vec<i32> = ::bits_to_words(bit_array, word_size, total_words);
|
||||
rs.encode(&message_words, total_words - message_size_in_words);
|
||||
let start_pad: i32 = total_bits % word_size;
|
||||
let message_bits: BitArray = BitArray::new();
|
||||
message_bits.append_bits(0, start_pad);
|
||||
for let message_word: i32 in message_words {
|
||||
message_bits.append_bits(message_word, word_size);
|
||||
}
|
||||
return message_bits;
|
||||
}
|
||||
|
||||
fn bits_to_words( stuffed_bits: &BitArray, word_size: i32, total_words: i32) -> Vec<i32> {
|
||||
let mut message: [i32; total_words] = [0; total_words];
|
||||
let mut i: i32;
|
||||
let mut n: i32;
|
||||
{
|
||||
i = 0;
|
||||
n = stuffed_bits.get_size() / word_size;
|
||||
while i < n {
|
||||
{
|
||||
let mut value: i32 = 0;
|
||||
{
|
||||
let mut j: i32 = 0;
|
||||
while j < word_size {
|
||||
{
|
||||
value |= if stuffed_bits.get(i * word_size + j) { (1 << word_size - j - 1) } else { 0 };
|
||||
}
|
||||
j += 1;
|
||||
}
|
||||
}
|
||||
|
||||
message[i] = value;
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
return message;
|
||||
}
|
||||
|
||||
fn get_g_f( word_size: i32) -> GenericGF {
|
||||
match word_size {
|
||||
4 =>
|
||||
{
|
||||
return GenericGF::AZTEC_PARAM;
|
||||
}
|
||||
6 =>
|
||||
{
|
||||
return GenericGF::AZTEC_DATA_6;
|
||||
}
|
||||
8 =>
|
||||
{
|
||||
return GenericGF::AZTEC_DATA_8;
|
||||
}
|
||||
10 =>
|
||||
{
|
||||
return GenericGF::AZTEC_DATA_10;
|
||||
}
|
||||
12 =>
|
||||
{
|
||||
return GenericGF::AZTEC_DATA_12;
|
||||
}
|
||||
_ =>
|
||||
{
|
||||
throw IllegalArgumentException::new(format!("Unsupported word size {}", word_size));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn stuff_bits( bits: &BitArray, word_size: i32) -> BitArray {
|
||||
let out: BitArray = BitArray::new();
|
||||
let n: i32 = bits.get_size();
|
||||
let mask: i32 = (1 << word_size) - 2;
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < n {
|
||||
{
|
||||
let mut word: i32 = 0;
|
||||
{
|
||||
let mut j: i32 = 0;
|
||||
while j < word_size {
|
||||
{
|
||||
if i + j >= n || bits.get(i + j) {
|
||||
word |= 1 << (word_size - 1 - j);
|
||||
}
|
||||
}
|
||||
j += 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (word & mask) == mask {
|
||||
out.append_bits(word & mask, word_size);
|
||||
i -= 1;
|
||||
} else if (word & mask) == 0 {
|
||||
out.append_bits(word | 1, word_size);
|
||||
i -= 1;
|
||||
} else {
|
||||
out.append_bits(word, word_size);
|
||||
}
|
||||
}
|
||||
i += word_size;
|
||||
}
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
fn total_bits_in_layer( layers: i32, compact: bool) -> i32 {
|
||||
return (( if compact { 88 } else { 112 }) + 16 * layers) * layers;
|
||||
}
|
||||
}
|
||||
|
||||
370
port_src/output/zxing/aztec/encoder/high_level_encoder.rs
Normal file
370
port_src/output/zxing/aztec/encoder/high_level_encoder.rs
Normal file
@@ -0,0 +1,370 @@
|
||||
/*
|
||||
* 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::aztec::encoder;
|
||||
|
||||
/**
|
||||
* This produces nearly optimal encodings of text into the first-level of
|
||||
* encoding used by Aztec code.
|
||||
*
|
||||
* It uses a dynamic algorithm. For each prefix of the string, it determines
|
||||
* a set of encodings that could lead to this prefix. We repeatedly add a
|
||||
* character and generate a new set of optimal encodings until we have read
|
||||
* through the entire input.
|
||||
*
|
||||
* @author Frank Yellin
|
||||
* @author Rustam Abdullaev
|
||||
*/
|
||||
|
||||
const MODE_NAMES: vec![Vec<String>; 5] = vec!["UPPER", "LOWER", "DIGIT", "MIXED", "PUNCT", ]
|
||||
;
|
||||
|
||||
// 5 bits
|
||||
const MODE_UPPER: i32 = 0;
|
||||
|
||||
// 5 bits
|
||||
const MODE_LOWER: i32 = 1;
|
||||
|
||||
// 4 bits
|
||||
const MODE_DIGIT: i32 = 2;
|
||||
|
||||
// 5 bits
|
||||
const MODE_MIXED: i32 = 3;
|
||||
|
||||
// 5 bits
|
||||
const MODE_PUNCT: i32 = 4;
|
||||
|
||||
// The Latch Table shows, for each pair of Modes, the optimal method for
|
||||
// getting from one mode to another. In the worst possible case, this can
|
||||
// be up to 14 bits. In the best possible case, we are already there!
|
||||
// The high half-word of each entry gives the number of bits.
|
||||
// The low half-word of each entry are the actual bits necessary to change
|
||||
const LATCH_TABLE: vec![vec![Vec<Vec<i32>>; 5]; 5] = vec![vec![0, // UPPER -> LOWER
|
||||
(5 << 16) + 28, // UPPER -> DIGIT
|
||||
(5 << 16) + 30, // UPPER -> MIXED
|
||||
(5 << 16) + 29, // UPPER -> MIXED -> PUNCT
|
||||
(10 << 16) + (29 << 5) + 30, ]
|
||||
, vec![// LOWER -> DIGIT -> UPPER
|
||||
(9 << 16) + (30 << 4) + 14, 0, // LOWER -> DIGIT
|
||||
(5 << 16) + 30, // LOWER -> MIXED
|
||||
(5 << 16) + 29, // LOWER -> MIXED -> PUNCT
|
||||
(10 << 16) + (29 << 5) + 30, ]
|
||||
, vec![// DIGIT -> UPPER
|
||||
(4 << 16) + 14, // DIGIT -> UPPER -> LOWER
|
||||
(9 << 16) + (14 << 5) + 28, 0, // DIGIT -> UPPER -> MIXED
|
||||
(9 << 16) + (14 << 5) + 29, (14 << 16) + (14 << 10) + (29 << 5) + 30, ]
|
||||
, vec![// MIXED -> UPPER
|
||||
(5 << 16) + 29, // MIXED -> LOWER
|
||||
(5 << 16) + 28, // MIXED -> UPPER -> DIGIT
|
||||
(10 << 16) + (29 << 5) + 30, 0, // MIXED -> PUNCT
|
||||
(5 << 16) + 30, ]
|
||||
, vec![// PUNCT -> UPPER
|
||||
(5 << 16) + 31, // PUNCT -> UPPER -> LOWER
|
||||
(10 << 16) + (31 << 5) + 28, // PUNCT -> UPPER -> DIGIT
|
||||
(10 << 16) + (31 << 5) + 30, // PUNCT -> UPPER -> MIXED
|
||||
(10 << 16) + (31 << 5) + 29, 0, ]
|
||||
, ]
|
||||
;
|
||||
|
||||
// A reverse mapping from [mode][char] to the encoding for that character
|
||||
// in that mode. An entry of 0 indicates no mapping exists.
|
||||
const CHAR_MAP: [[i32; 256]; 5] = [[0; 256]; 5];
|
||||
|
||||
// A map showing the available shift codes. (The shifts to BINARY are not
|
||||
// shown
|
||||
// mode shift codes, per table
|
||||
const SHIFT_TABLE: [[i32; 6]; 6] = [[0; 6]; 6];
|
||||
pub struct HighLevelEncoder {
|
||||
|
||||
let text: Vec<i8>;
|
||||
|
||||
let mut charset: Charset;
|
||||
}
|
||||
|
||||
impl HighLevelEncoder {
|
||||
|
||||
static {
|
||||
CHAR_MAP[MODE_UPPER][' '] = 1;
|
||||
{
|
||||
let mut c: i32 = 'A';
|
||||
while c <= 'Z' {
|
||||
{
|
||||
CHAR_MAP[MODE_UPPER][c] = c - 'A' + 2;
|
||||
}
|
||||
c += 1;
|
||||
}
|
||||
}
|
||||
|
||||
CHAR_MAP[MODE_LOWER][' '] = 1;
|
||||
{
|
||||
let mut c: i32 = 'a';
|
||||
while c <= 'z' {
|
||||
{
|
||||
CHAR_MAP[MODE_LOWER][c] = c - 'a' + 2;
|
||||
}
|
||||
c += 1;
|
||||
}
|
||||
}
|
||||
|
||||
CHAR_MAP[MODE_DIGIT][' '] = 1;
|
||||
{
|
||||
let mut c: i32 = '0';
|
||||
while c <= '9' {
|
||||
{
|
||||
CHAR_MAP[MODE_DIGIT][c] = c - '0' + 2;
|
||||
}
|
||||
c += 1;
|
||||
}
|
||||
}
|
||||
|
||||
CHAR_MAP[MODE_DIGIT][','] = 12;
|
||||
CHAR_MAP[MODE_DIGIT]['.'] = 13;
|
||||
let mixed_table: vec![Vec<i32>; 28] = vec!['\0', ' ', '\1', '\2', '\3', '\4', '\5', '\6', '\7', '\b', '\t', '\n', '\13', '\f', '\r', '\33', '\34', '\35', '\36', '\37', '@', '\\', '^', '_', '`', '|', '~', '\177', ]
|
||||
;
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < mixed_table.len() {
|
||||
{
|
||||
CHAR_MAP[MODE_MIXED][mixed_table[i]] = i;
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
let punct_table: vec![Vec<i32>; 31] = vec!['\0', '\r', '\0', '\0', '\0', '\0', '!', '\'', '#', '$', '%', '&', '\'', '(', ')', '*', '+', ',', '-', '.', '/', ':', ';', '<', '=', '>', '?', '[', ']', '{', '}', ]
|
||||
;
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < punct_table.len() {
|
||||
{
|
||||
if punct_table[i] > 0 {
|
||||
CHAR_MAP[MODE_PUNCT][punct_table[i]] = i;
|
||||
}
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static {
|
||||
for let table: Vec<i32> in SHIFT_TABLE {
|
||||
Arrays::fill(&table, -1);
|
||||
}
|
||||
SHIFT_TABLE[MODE_UPPER][MODE_PUNCT] = 0;
|
||||
SHIFT_TABLE[MODE_LOWER][MODE_PUNCT] = 0;
|
||||
SHIFT_TABLE[MODE_LOWER][MODE_UPPER] = 28;
|
||||
SHIFT_TABLE[MODE_MIXED][MODE_PUNCT] = 0;
|
||||
SHIFT_TABLE[MODE_DIGIT][MODE_PUNCT] = 0;
|
||||
SHIFT_TABLE[MODE_DIGIT][MODE_UPPER] = 15;
|
||||
}
|
||||
|
||||
pub fn new( text: &Vec<i8>) -> HighLevelEncoder {
|
||||
let .text = text;
|
||||
let .charset = null;
|
||||
}
|
||||
|
||||
pub fn new( text: &Vec<i8>, charset: &Charset) -> HighLevelEncoder {
|
||||
let .text = text;
|
||||
let .charset = charset;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return text represented by this encoder encoded as a {@link BitArray}
|
||||
*/
|
||||
pub fn encode(&self) -> BitArray {
|
||||
let initial_state: State = State::INITIAL_STATE;
|
||||
if self.charset != null {
|
||||
let eci: CharacterSetECI = CharacterSetECI::get_character_set_e_c_i(&self.charset);
|
||||
if null == eci {
|
||||
throw IllegalArgumentException::new(format!("No ECI code for character set {}", self.charset));
|
||||
}
|
||||
initial_state = initial_state.append_f_l_gn(&eci.get_value());
|
||||
}
|
||||
let mut states: Collection<State> = Collections::singleton_list(initial_state);
|
||||
{
|
||||
let mut index: i32 = 0;
|
||||
while index < self.text.len() {
|
||||
{
|
||||
let pair_code: i32;
|
||||
let next_char: i32 = if index + 1 < self.text.len() { self.text[index + 1] } else { 0 };
|
||||
match self.text[index] {
|
||||
'\r' =>
|
||||
{
|
||||
pair_code = if next_char == '\n' { 2 } else { 0 };
|
||||
break;
|
||||
}
|
||||
'.' =>
|
||||
{
|
||||
pair_code = if next_char == ' ' { 3 } else { 0 };
|
||||
break;
|
||||
}
|
||||
',' =>
|
||||
{
|
||||
pair_code = if next_char == ' ' { 4 } else { 0 };
|
||||
break;
|
||||
}
|
||||
':' =>
|
||||
{
|
||||
pair_code = if next_char == ' ' { 5 } else { 0 };
|
||||
break;
|
||||
}
|
||||
_ =>
|
||||
{
|
||||
pair_code = 0;
|
||||
}
|
||||
}
|
||||
if pair_code > 0 {
|
||||
// We have one of the four special PUNCT pairs. Treat them specially.
|
||||
// Get a new set of states for the two new characters.
|
||||
states = ::update_state_list_for_pair(&states, index, pair_code);
|
||||
index += 1;
|
||||
} else {
|
||||
// Get a new set of states for the new character.
|
||||
states = self.update_state_list_for_char(&states, index);
|
||||
}
|
||||
}
|
||||
index += 1;
|
||||
}
|
||||
}
|
||||
|
||||
// We are left with a set of states. Find the shortest one.
|
||||
let min_state: State = Collections::min(&states, Comparator<State>::new() {
|
||||
|
||||
pub fn compare(&self, a: &State, b: &State) -> i32 {
|
||||
return a.get_bit_count() - b.get_bit_count();
|
||||
}
|
||||
});
|
||||
// Convert it to a bit array, and return.
|
||||
return min_state.to_bit_array(&self.text);
|
||||
}
|
||||
|
||||
// We update a set of states for a new character by updating each state
|
||||
// for the new character, merging the results, and then removing the
|
||||
// non-optimal states.
|
||||
fn update_state_list_for_char(&self, states: &Iterable<State>, index: i32) -> Collection<State> {
|
||||
let result: Collection<State> = LinkedList<>::new();
|
||||
for let state: State in states {
|
||||
self.update_state_for_char(state, index, &result);
|
||||
}
|
||||
return ::simplify_states(&result);
|
||||
}
|
||||
|
||||
// Return a set of states that represent the possible ways of updating this
|
||||
// state for the next character. The resulting set of states are added to
|
||||
// the "result" list.
|
||||
fn update_state_for_char(&self, state: &State, index: i32, result: &Collection<State>) {
|
||||
let ch: char = (self.text[index] & 0xFF) as char;
|
||||
let char_in_current_table: bool = CHAR_MAP[state.get_mode()][ch] > 0;
|
||||
let state_no_binary: State = null;
|
||||
{
|
||||
let mut mode: i32 = 0;
|
||||
while mode <= MODE_PUNCT {
|
||||
{
|
||||
let char_in_mode: i32 = CHAR_MAP[mode][ch];
|
||||
if char_in_mode > 0 {
|
||||
if state_no_binary == null {
|
||||
// Only create stateNoBinary the first time it's required.
|
||||
state_no_binary = state.end_binary_shift(index);
|
||||
}
|
||||
// Try generating the character by latching to its mode
|
||||
if !char_in_current_table || mode == state.get_mode() || mode == MODE_DIGIT {
|
||||
// If the character is in the current table, we don't want to latch to
|
||||
// any other mode except possibly digit (which uses only 4 bits). Any
|
||||
// other latch would be equally successful *after* this character, and
|
||||
// so wouldn't save any bits.
|
||||
let latch_state: State = state_no_binary.latch_and_append(mode, char_in_mode);
|
||||
result.add(latch_state);
|
||||
}
|
||||
// Try generating the character by switching to its mode.
|
||||
if !char_in_current_table && SHIFT_TABLE[state.get_mode()][mode] >= 0 {
|
||||
// It never makes sense to temporarily shift to another mode if the
|
||||
// character exists in the current mode. That can never save bits.
|
||||
let shift_state: State = state_no_binary.shift_and_append(mode, char_in_mode);
|
||||
result.add(shift_state);
|
||||
}
|
||||
}
|
||||
}
|
||||
mode += 1;
|
||||
}
|
||||
}
|
||||
|
||||
if state.get_binary_shift_byte_count() > 0 || CHAR_MAP[state.get_mode()][ch] == 0 {
|
||||
// It's never worthwhile to go into binary shift mode if you're not already
|
||||
// in binary shift mode, and the character exists in your current mode.
|
||||
// That can never save bits over just outputting the char in the current mode.
|
||||
let binary_state: State = state.add_binary_shift_char(index);
|
||||
result.add(binary_state);
|
||||
}
|
||||
}
|
||||
|
||||
fn update_state_list_for_pair( states: &Iterable<State>, index: i32, pair_code: i32) -> Collection<State> {
|
||||
let result: Collection<State> = LinkedList<>::new();
|
||||
for let state: State in states {
|
||||
::update_state_for_pair(state, index, pair_code, &result);
|
||||
}
|
||||
return ::simplify_states(&result);
|
||||
}
|
||||
|
||||
fn update_state_for_pair( state: &State, index: i32, pair_code: i32, result: &Collection<State>) {
|
||||
let state_no_binary: State = state.end_binary_shift(index);
|
||||
// Possibility 1. Latch to MODE_PUNCT, and then append this code
|
||||
result.add(&state_no_binary.latch_and_append(MODE_PUNCT, pair_code));
|
||||
if state.get_mode() != MODE_PUNCT {
|
||||
// Possibility 2. Shift to MODE_PUNCT, and then append this code.
|
||||
// Every state except MODE_PUNCT (handled above) can shift
|
||||
result.add(&state_no_binary.shift_and_append(MODE_PUNCT, pair_code));
|
||||
}
|
||||
if pair_code == 3 || pair_code == 4 {
|
||||
// both characters are in DIGITS. Sometimes better to just add two digits
|
||||
let digit_state: State = state_no_binary.latch_and_append(MODE_DIGIT, // period or comma in DIGIT
|
||||
16 - pair_code).latch_and_append(MODE_DIGIT, // space in DIGIT
|
||||
1);
|
||||
result.add(digit_state);
|
||||
}
|
||||
if state.get_binary_shift_byte_count() > 0 {
|
||||
// It only makes sense to do the characters as binary if we're already
|
||||
// in binary mode.
|
||||
let binary_state: State = state.add_binary_shift_char(index).add_binary_shift_char(index + 1);
|
||||
result.add(binary_state);
|
||||
}
|
||||
}
|
||||
|
||||
fn simplify_states( states: &Iterable<State>) -> Collection<State> {
|
||||
let result: Deque<State> = LinkedList<>::new();
|
||||
for let new_state: State in states {
|
||||
let mut add: bool = true;
|
||||
{
|
||||
let iterator: Iterator<State> = result.iterator();
|
||||
while iterator.has_next(){
|
||||
let old_state: State = iterator.next();
|
||||
if old_state.is_better_than_or_equal_to(new_state) {
|
||||
add = false;
|
||||
break;
|
||||
}
|
||||
if new_state.is_better_than_or_equal_to(old_state) {
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if add {
|
||||
result.add_first(new_state);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
45
port_src/output/zxing/aztec/encoder/simple_token.rs
Normal file
45
port_src/output/zxing/aztec/encoder/simple_token.rs
Normal file
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* 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::aztec::encoder;
|
||||
|
||||
struct SimpleToken {
|
||||
super: Token;
|
||||
|
||||
// For normal words, indicates value and bitCount
|
||||
let value: i16;
|
||||
|
||||
let bit_count: i16;
|
||||
}
|
||||
|
||||
impl SimpleToken {
|
||||
|
||||
fn new( previous: &Token, value: i32, bit_count: i32) -> SimpleToken {
|
||||
super(previous);
|
||||
let .value = value as i16;
|
||||
let .bitCount = bit_count as i16;
|
||||
}
|
||||
|
||||
fn append_to(&self, bit_array: &BitArray, text: &Vec<i8>) {
|
||||
bit_array.append_bits(self.value, self.bit_count);
|
||||
}
|
||||
|
||||
pub fn to_string(&self) -> String {
|
||||
let mut value: i32 = self.value & ((1 << self.bit_count) - 1);
|
||||
value |= 1 << self.bit_count;
|
||||
return '<' + Integer::to_binary_string(value | (1 << self.bit_count))::substring(1) + '>';
|
||||
}
|
||||
}
|
||||
|
||||
211
port_src/output/zxing/aztec/encoder/state.rs
Normal file
211
port_src/output/zxing/aztec/encoder/state.rs
Normal file
@@ -0,0 +1,211 @@
|
||||
/*
|
||||
* 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::aztec::encoder;
|
||||
|
||||
/**
|
||||
* State represents all information about a sequence necessary to generate the current output.
|
||||
* Note that a state is immutable.
|
||||
*/
|
||||
|
||||
const INITIAL_STATE: State = State::new(Token::EMPTY, HighLevelEncoder::MODE_UPPER, 0, 0);
|
||||
struct State {
|
||||
|
||||
// The current mode of the encoding (or the mode to which we'll return if
|
||||
// we're in Binary Shift mode.
|
||||
let mode: i32;
|
||||
|
||||
// The list of tokens that we output. If we are in Binary Shift mode, this
|
||||
// token list does *not* yet included the token for those bytes
|
||||
let token: Token;
|
||||
|
||||
// If non-zero, the number of most recent bytes that should be output
|
||||
// in Binary Shift mode.
|
||||
let binary_shift_byte_count: i32;
|
||||
|
||||
// The total number of bits generated (including Binary Shift).
|
||||
let bit_count: i32;
|
||||
|
||||
let binary_shift_cost: i32;
|
||||
}
|
||||
|
||||
impl State {
|
||||
|
||||
fn new( token: &Token, mode: i32, binary_bytes: i32, bit_count: i32) -> State {
|
||||
let .token = token;
|
||||
let .mode = mode;
|
||||
let .binaryShiftByteCount = binary_bytes;
|
||||
let .bitCount = bit_count;
|
||||
let .binaryShiftCost = ::calculate_binary_shift_cost(binary_bytes);
|
||||
}
|
||||
|
||||
fn get_mode(&self) -> i32 {
|
||||
return self.mode;
|
||||
}
|
||||
|
||||
fn get_token(&self) -> Token {
|
||||
return self.token;
|
||||
}
|
||||
|
||||
fn get_binary_shift_byte_count(&self) -> i32 {
|
||||
return self.binary_shift_byte_count;
|
||||
}
|
||||
|
||||
fn get_bit_count(&self) -> i32 {
|
||||
return self.bit_count;
|
||||
}
|
||||
|
||||
fn append_f_l_gn(&self, eci: i32) -> State {
|
||||
// 0: FLG(n)
|
||||
let result: State = self.shift_and_append(HighLevelEncoder::MODE_PUNCT, 0);
|
||||
let mut token: Token = result.token;
|
||||
let bits_added: i32 = 3;
|
||||
if eci < 0 {
|
||||
// 0: FNC1
|
||||
token = token.add(0, 3);
|
||||
} else if eci > 999999 {
|
||||
throw IllegalArgumentException::new("ECI code must be between 0 and 999999");
|
||||
} else {
|
||||
let eci_digits: Vec<i8> = Integer::to_string(eci)::get_bytes(StandardCharsets::ISO_8859_1);
|
||||
// 1-6: number of ECI digits
|
||||
token = token.add(eci_digits.len(), 3);
|
||||
for let eci_digit: i8 in eci_digits {
|
||||
token = token.add(eci_digit - '0' + 2, 4);
|
||||
}
|
||||
bits_added += eci_digits.len() * 4;
|
||||
}
|
||||
return State::new(token, self.mode, 0, self.bit_count + bits_added);
|
||||
}
|
||||
|
||||
// Create a new state representing this state with a latch to a (not
|
||||
// necessary different) mode, and then a code.
|
||||
fn latch_and_append(&self, mode: i32, value: i32) -> State {
|
||||
let bit_count: i32 = self.bitCount;
|
||||
let mut token: Token = self.token;
|
||||
if mode != self.mode {
|
||||
let latch: i32 = HighLevelEncoder::LATCH_TABLE[self.mode][mode];
|
||||
token = token.add(latch & 0xFFFF, latch >> 16);
|
||||
bit_count += latch >> 16;
|
||||
}
|
||||
let latch_mode_bit_count: i32 = if mode == HighLevelEncoder::MODE_DIGIT { 4 } else { 5 };
|
||||
token = token.add(value, latch_mode_bit_count);
|
||||
return State::new(token, mode, 0, bit_count + latch_mode_bit_count);
|
||||
}
|
||||
|
||||
// Create a new state representing this state, with a temporary shift
|
||||
// to a different mode to output a single value.
|
||||
fn shift_and_append(&self, mode: i32, value: i32) -> State {
|
||||
let mut token: Token = self.token;
|
||||
let this_mode_bit_count: i32 = if self.mode == HighLevelEncoder::MODE_DIGIT { 4 } else { 5 };
|
||||
// Shifts exist only to UPPER and PUNCT, both with tokens size 5.
|
||||
token = token.add(HighLevelEncoder::SHIFT_TABLE[self.mode][mode], this_mode_bit_count);
|
||||
token = token.add(value, 5);
|
||||
return State::new(token, self.mode, 0, self.bitCount + this_mode_bit_count + 5);
|
||||
}
|
||||
|
||||
// Create a new state representing this state, but an additional character
|
||||
// output in Binary Shift mode.
|
||||
fn add_binary_shift_char(&self, index: i32) -> State {
|
||||
let mut token: Token = self.token;
|
||||
let mut mode: i32 = self.mode;
|
||||
let bit_count: i32 = self.bitCount;
|
||||
if self.mode == HighLevelEncoder::MODE_PUNCT || self.mode == HighLevelEncoder::MODE_DIGIT {
|
||||
let latch: i32 = HighLevelEncoder::LATCH_TABLE[mode][HighLevelEncoder::MODE_UPPER];
|
||||
token = token.add(latch & 0xFFFF, latch >> 16);
|
||||
bit_count += latch >> 16;
|
||||
mode = HighLevelEncoder::MODE_UPPER;
|
||||
}
|
||||
let delta_bit_count: i32 = if (self.binary_shift_byte_count == 0 || self.binary_shift_byte_count == 31) { 18 } else { if (self.binary_shift_byte_count == 62) { 9 } else { 8 } };
|
||||
let mut result: State = State::new(token, mode, self.binary_shift_byte_count + 1, bit_count + delta_bit_count);
|
||||
if result.binaryShiftByteCount == 2047 + 31 {
|
||||
// The string is as long as it's allowed to be. We should end it.
|
||||
result = result.end_binary_shift(index + 1);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// Create the state identical to this one, but we are no longer in
|
||||
// Binary Shift mode.
|
||||
fn end_binary_shift(&self, index: i32) -> State {
|
||||
if self.binary_shift_byte_count == 0 {
|
||||
return self;
|
||||
}
|
||||
let mut token: Token = self.token;
|
||||
token = token.add_binary_shift(index - self.binary_shift_byte_count, self.binary_shift_byte_count);
|
||||
return State::new(token, self.mode, 0, self.bitCount);
|
||||
}
|
||||
|
||||
// Returns true if "this" state is better (or equal) to be in than "that"
|
||||
// state under all possible circumstances.
|
||||
fn is_better_than_or_equal_to(&self, other: &State) -> bool {
|
||||
let new_mode_bit_count: i32 = self.bitCount + (HighLevelEncoder::LATCH_TABLE[self.mode][other.mode] >> 16);
|
||||
if self.binaryShiftByteCount < other.binaryShiftByteCount {
|
||||
// add additional B/S encoding cost of other, if any
|
||||
new_mode_bit_count += other.binaryShiftCost - self.binaryShiftCost;
|
||||
} else if self.binaryShiftByteCount > other.binaryShiftByteCount && other.binaryShiftByteCount > 0 {
|
||||
// maximum possible additional cost (we end up exceeding the 31 byte boundary and other state can stay beneath it)
|
||||
new_mode_bit_count += 10;
|
||||
}
|
||||
return new_mode_bit_count <= other.bitCount;
|
||||
}
|
||||
|
||||
fn to_bit_array(&self, text: &Vec<i8>) -> BitArray {
|
||||
let symbols: List<Token> = ArrayList<>::new();
|
||||
{
|
||||
let mut token: Token = self.end_binary_shift(text.len()).token;
|
||||
while token != null {
|
||||
{
|
||||
symbols.add(token);
|
||||
}
|
||||
token = token.get_previous();
|
||||
}
|
||||
}
|
||||
|
||||
let bit_array: BitArray = BitArray::new();
|
||||
// Add each token to the result in forward order
|
||||
{
|
||||
let mut i: i32 = symbols.size() - 1;
|
||||
while i >= 0 {
|
||||
{
|
||||
symbols.get(i).append_to(bit_array, &text);
|
||||
}
|
||||
i -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
return bit_array;
|
||||
}
|
||||
|
||||
pub fn to_string(&self) -> String {
|
||||
return String::format("%s bits=%d bytes=%d", HighLevelEncoder::MODE_NAMES[self.mode], self.bit_count, self.binary_shift_byte_count);
|
||||
}
|
||||
|
||||
fn calculate_binary_shift_cost( binary_shift_byte_count: i32) -> i32 {
|
||||
if binary_shift_byte_count > 62 {
|
||||
// B/S with extended length
|
||||
return 21;
|
||||
}
|
||||
if binary_shift_byte_count > 31 {
|
||||
// two B/S
|
||||
return 20;
|
||||
}
|
||||
if binary_shift_byte_count > 0 {
|
||||
// one B/S
|
||||
return 10;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
46
port_src/output/zxing/aztec/encoder/token.rs
Normal file
46
port_src/output/zxing/aztec/encoder/token.rs
Normal file
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* 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::aztec::encoder;
|
||||
|
||||
|
||||
const EMPTY: Token = SimpleToken::new(null, 0, 0);
|
||||
struct Token {
|
||||
|
||||
let previous: Token;
|
||||
}
|
||||
|
||||
impl Token {
|
||||
|
||||
fn new( previous: &Token) -> Token {
|
||||
let .previous = previous;
|
||||
}
|
||||
|
||||
fn get_previous(&self) -> Token {
|
||||
return self.previous;
|
||||
}
|
||||
|
||||
fn add(&self, value: i32, bit_count: i32) -> Token {
|
||||
return SimpleToken::new(self, value, bit_count);
|
||||
}
|
||||
|
||||
fn add_binary_shift(&self, start: i32, byte_count: i32) -> Token {
|
||||
//int bitCount = (byteCount * 8) + (byteCount <= 31 ? 10 : byteCount <= 62 ? 20 : 21);
|
||||
return BinaryShiftToken::new(self, start, byte_count);
|
||||
}
|
||||
|
||||
fn append_to(&self, bit_array: &BitArray, text: &Vec<i8>) ;
|
||||
}
|
||||
|
||||
43
port_src/output/zxing/barcode_format.rs
Normal file
43
port_src/output/zxing/barcode_format.rs
Normal file
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* Enumerates barcode formats known to this package. Please keep alphabetized.
|
||||
*
|
||||
* @author Sean Owen
|
||||
*/
|
||||
pub enum BarcodeFormat {
|
||||
|
||||
/** Aztec 2D barcode format. */
|
||||
AZTEC(), /** CODABAR 1D format. */
|
||||
CODABAR(), /** Code 39 1D format. */
|
||||
CODE_39(), /** Code 93 1D format. */
|
||||
CODE_93(), /** Code 128 1D format. */
|
||||
CODE_128(), /** Data Matrix 2D barcode format. */
|
||||
DATA_MATRIX(), /** EAN-8 1D format. */
|
||||
EAN_8(), /** EAN-13 1D format. */
|
||||
EAN_13(), /** ITF (Interleaved Two of Five) 1D format. */
|
||||
ITF(), /** MaxiCode 2D barcode format. */
|
||||
MAXICODE(), /** PDF417 format. */
|
||||
PDF_417(), /** QR Code 2D barcode format. */
|
||||
QR_CODE(), /** RSS 14 */
|
||||
RSS_14(), /** RSS EXPANDED */
|
||||
RSS_EXPANDED(), /** UPC-A 1D format. */
|
||||
UPC_A(), /** UPC-E 1D format. */
|
||||
UPC_E(), /** UPC/EAN extension format. Not a stand-alone format. */
|
||||
UPC_EAN_EXTENSION()
|
||||
}
|
||||
86
port_src/output/zxing/binarizer.rs
Normal file
86
port_src/output/zxing/binarizer.rs
Normal file
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* This class hierarchy provides a set of methods to convert luminance data to 1 bit data.
|
||||
* It allows the algorithm to vary polymorphically, for example allowing a very expensive
|
||||
* thresholding technique for servers and a fast one for mobile. It also permits the implementation
|
||||
* to vary, e.g. a JNI version for Android and a Java fallback version for other platforms.
|
||||
*
|
||||
* @author dswitkin@google.com (Daniel Switkin)
|
||||
*/
|
||||
pub struct Binarizer {
|
||||
|
||||
let source: LuminanceSource;
|
||||
}
|
||||
|
||||
impl Binarizer {
|
||||
|
||||
pub fn new( source: &LuminanceSource) -> Binarizer {
|
||||
let .source = source;
|
||||
}
|
||||
|
||||
pub fn get_luminance_source(&self) -> LuminanceSource {
|
||||
return self.source;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts one row of luminance data to 1 bit data. May actually do the conversion, or return
|
||||
* cached data. Callers should assume this method is expensive and call it as seldom as possible.
|
||||
* This method is intended for decoding 1D barcodes and may choose to apply sharpening.
|
||||
* For callers which only examine one row of pixels at a time, the same BitArray should be reused
|
||||
* and passed in with each call for performance. However it is legal to keep more than one row
|
||||
* at a time if needed.
|
||||
*
|
||||
* @param y The row to fetch, which must be in [0, bitmap height)
|
||||
* @param row An optional preallocated array. If null or too small, it will be ignored.
|
||||
* If used, the Binarizer will call BitArray.clear(). Always use the returned object.
|
||||
* @return The array of bits for this row (true means black).
|
||||
* @throws NotFoundException if row can't be binarized
|
||||
*/
|
||||
pub fn get_black_row(&self, y: i32, row: &BitArray) -> /* throws NotFoundException */Result<BitArray, Rc<Exception>> ;
|
||||
|
||||
/**
|
||||
* Converts a 2D array of luminance data to 1 bit data. As above, assume this method is expensive
|
||||
* and do not call it repeatedly. This method is intended for decoding 2D barcodes and may or
|
||||
* may not apply sharpening. Therefore, a row from this matrix may not be identical to one
|
||||
* fetched using getBlackRow(), so don't mix and match between them.
|
||||
*
|
||||
* @return The 2D array of bits for the image (true means black).
|
||||
* @throws NotFoundException if image can't be binarized to make a matrix
|
||||
*/
|
||||
pub fn get_black_matrix(&self) -> /* throws NotFoundException */Result<BitMatrix, Rc<Exception>> ;
|
||||
|
||||
/**
|
||||
* Creates a new object with the same type as this Binarizer implementation, but with pristine
|
||||
* state. This is needed because Binarizer implementations may be stateful, e.g. keeping a cache
|
||||
* of 1 bit data. See Effective Java for why we can't use Java's clone() method.
|
||||
*
|
||||
* @param source The LuminanceSource this Binarizer will operate on.
|
||||
* @return A new concrete Binarizer implementation object.
|
||||
*/
|
||||
pub fn create_binarizer(&self, source: &LuminanceSource) -> Binarizer ;
|
||||
|
||||
pub fn get_width(&self) -> i32 {
|
||||
return self.source.get_width();
|
||||
}
|
||||
|
||||
pub fn get_height(&self) -> i32 {
|
||||
return self.source.get_height();
|
||||
}
|
||||
}
|
||||
|
||||
153
port_src/output/zxing/binary_bitmap.rs
Normal file
153
port_src/output/zxing/binary_bitmap.rs
Normal file
@@ -0,0 +1,153 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* This class is the core bitmap class used by ZXing to represent 1 bit data. Reader objects
|
||||
* accept a BinaryBitmap and attempt to decode it.
|
||||
*
|
||||
* @author dswitkin@google.com (Daniel Switkin)
|
||||
*/
|
||||
pub struct BinaryBitmap {
|
||||
|
||||
let binarizer: Binarizer;
|
||||
|
||||
let mut matrix: BitMatrix;
|
||||
}
|
||||
|
||||
impl BinaryBitmap {
|
||||
|
||||
pub fn new( binarizer: &Binarizer) -> BinaryBitmap {
|
||||
if binarizer == null {
|
||||
throw IllegalArgumentException::new("Binarizer must be non-null.");
|
||||
}
|
||||
let .binarizer = binarizer;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The width of the bitmap.
|
||||
*/
|
||||
pub fn get_width(&self) -> i32 {
|
||||
return self.binarizer.get_width();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The height of the bitmap.
|
||||
*/
|
||||
pub fn get_height(&self) -> i32 {
|
||||
return self.binarizer.get_height();
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts one row of luminance data to 1 bit data. May actually do the conversion, or return
|
||||
* cached data. Callers should assume this method is expensive and call it as seldom as possible.
|
||||
* This method is intended for decoding 1D barcodes and may choose to apply sharpening.
|
||||
*
|
||||
* @param y The row to fetch, which must be in [0, bitmap height)
|
||||
* @param row An optional preallocated array. If null or too small, it will be ignored.
|
||||
* If used, the Binarizer will call BitArray.clear(). Always use the returned object.
|
||||
* @return The array of bits for this row (true means black).
|
||||
* @throws NotFoundException if row can't be binarized
|
||||
*/
|
||||
pub fn get_black_row(&self, y: i32, row: &BitArray) -> /* throws NotFoundException */Result<BitArray, Rc<Exception>> {
|
||||
return Ok(self.binarizer.get_black_row(y, row));
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a 2D array of luminance data to 1 bit. As above, assume this method is expensive
|
||||
* and do not call it repeatedly. This method is intended for decoding 2D barcodes and may or
|
||||
* may not apply sharpening. Therefore, a row from this matrix may not be identical to one
|
||||
* fetched using getBlackRow(), so don't mix and match between them.
|
||||
*
|
||||
* @return The 2D array of bits for the image (true means black).
|
||||
* @throws NotFoundException if image can't be binarized to make a matrix
|
||||
*/
|
||||
pub fn get_black_matrix(&self) -> /* throws NotFoundException */Result<BitMatrix, Rc<Exception>> {
|
||||
// 2. This work will only be done once even if the caller installs multiple 2D Readers.
|
||||
if self.matrix == null {
|
||||
self.matrix = self.binarizer.get_black_matrix();
|
||||
}
|
||||
return Ok(self.matrix);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Whether this bitmap can be cropped.
|
||||
*/
|
||||
pub fn is_crop_supported(&self) -> bool {
|
||||
return self.binarizer.get_luminance_source().is_crop_supported();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new object with cropped image data. Implementations may keep a reference to the
|
||||
* original data rather than a copy. Only callable if isCropSupported() is true.
|
||||
*
|
||||
* @param left The left coordinate, which must be in [0,getWidth())
|
||||
* @param top The top coordinate, which must be in [0,getHeight())
|
||||
* @param width The width of the rectangle to crop.
|
||||
* @param height The height of the rectangle to crop.
|
||||
* @return A cropped version of this object.
|
||||
*/
|
||||
pub fn crop(&self, left: i32, top: i32, width: i32, height: i32) -> BinaryBitmap {
|
||||
let new_source: LuminanceSource = self.binarizer.get_luminance_source().crop(left, top, width, height);
|
||||
return BinaryBitmap::new(&self.binarizer.create_binarizer(new_source));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Whether this bitmap supports counter-clockwise rotation.
|
||||
*/
|
||||
pub fn is_rotate_supported(&self) -> bool {
|
||||
return self.binarizer.get_luminance_source().is_rotate_supported();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new object with rotated image data by 90 degrees counterclockwise.
|
||||
* Only callable if {@link #isRotateSupported()} is true.
|
||||
*
|
||||
* @return A rotated version of this object.
|
||||
*/
|
||||
pub fn rotate_counter_clockwise(&self) -> BinaryBitmap {
|
||||
let new_source: LuminanceSource = self.binarizer.get_luminance_source().rotate_counter_clockwise();
|
||||
return BinaryBitmap::new(&self.binarizer.create_binarizer(new_source));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new object with rotated image data by 45 degrees counterclockwise.
|
||||
* Only callable if {@link #isRotateSupported()} is true.
|
||||
*
|
||||
* @return A rotated version of this object.
|
||||
*/
|
||||
pub fn rotate_counter_clockwise45(&self) -> BinaryBitmap {
|
||||
let new_source: LuminanceSource = self.binarizer.get_luminance_source().rotate_counter_clockwise45();
|
||||
return BinaryBitmap::new(&self.binarizer.create_binarizer(new_source));
|
||||
}
|
||||
|
||||
pub fn to_string(&self) -> String {
|
||||
let tryResult1 = 0;
|
||||
'try1: loop {
|
||||
{
|
||||
return self.get_black_matrix().to_string();
|
||||
}
|
||||
break 'try1
|
||||
}
|
||||
match tryResult1 {
|
||||
catch ( e: &NotFoundException) {
|
||||
return "";
|
||||
} 0 => break
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
53
port_src/output/zxing/checksum_exception.rs
Normal file
53
port_src/output/zxing/checksum_exception.rs
Normal file
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* Thrown when a barcode was successfully detected and decoded, but
|
||||
* was not returned because its checksum feature failed.
|
||||
*
|
||||
* @author Sean Owen
|
||||
*/
|
||||
|
||||
const INSTANCE: ChecksumException = ChecksumException::new();
|
||||
pub struct ChecksumException {
|
||||
super: ReaderException;
|
||||
}
|
||||
|
||||
impl ChecksumException {
|
||||
|
||||
static {
|
||||
// since it's meaningless
|
||||
INSTANCE::set_stack_trace(NO_TRACE);
|
||||
}
|
||||
|
||||
fn new() -> ChecksumException {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
fn new( cause: &Throwable) -> ChecksumException {
|
||||
super(&cause);
|
||||
}
|
||||
|
||||
pub fn get_checksum_instance() -> ChecksumException {
|
||||
return if is_stack_trace { ChecksumException::new() } else { INSTANCE };
|
||||
}
|
||||
|
||||
pub fn get_checksum_instance( cause: &Throwable) -> ChecksumException {
|
||||
return if is_stack_trace { ChecksumException::new(&cause) } else { INSTANCE };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* 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::client::result;
|
||||
|
||||
/**
|
||||
* <p>See
|
||||
* <a href="http://www.nttdocomo.co.jp/english/service/imode/make/content/barcode/about/s2.html">
|
||||
* DoCoMo's documentation</a> about the result types represented by subclasses of this class.</p>
|
||||
*
|
||||
* <p>Thanks to Jeff Griffin for proposing rewrite of these classes that relies less
|
||||
* on exception-based mechanisms during parsing.</p>
|
||||
*
|
||||
* @author Sean Owen
|
||||
*/
|
||||
struct AbstractDoCoMoResultParser {
|
||||
super: ResultParser;
|
||||
}
|
||||
|
||||
impl AbstractDoCoMoResultParser {
|
||||
|
||||
fn match_do_co_mo_prefixed_field( prefix: &String, raw_text: &String) -> Vec<String> {
|
||||
return match_prefixed_field(&prefix, &raw_text, ';', true);
|
||||
}
|
||||
|
||||
fn match_single_do_co_mo_prefixed_field( prefix: &String, raw_text: &String, trim: bool) -> String {
|
||||
return match_single_prefixed_field(&prefix, &raw_text, ';', trim);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* 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::client::result;
|
||||
|
||||
/**
|
||||
* Implements KDDI AU's address book format. See
|
||||
* <a href="http://www.au.kddi.com/ezfactory/tec/two_dimensions/index.html">
|
||||
* http://www.au.kddi.com/ezfactory/tec/two_dimensions/index.html</a>.
|
||||
* (Thanks to Yuzo for translating!)
|
||||
*
|
||||
* @author Sean Owen
|
||||
*/
|
||||
pub struct AddressBookAUResultParser {
|
||||
super: ResultParser;
|
||||
}
|
||||
|
||||
impl AddressBookAUResultParser {
|
||||
|
||||
pub fn parse(&self, result: &Result) -> AddressBookParsedResult {
|
||||
let raw_text: String = get_massaged_text(result);
|
||||
// MEMORY is mandatory; seems like a decent indicator, as does end-of-record separator CR/LF
|
||||
if !raw_text.contains("MEMORY") || !raw_text.contains("\r\n") {
|
||||
return null;
|
||||
}
|
||||
// NAME1 and NAME2 have specific uses, namely written name and pronunciation, respectively.
|
||||
// Therefore we treat them specially instead of as an array of names.
|
||||
let name: String = match_single_prefixed_field("NAME1:", &raw_text, '\r', true);
|
||||
let pronunciation: String = match_single_prefixed_field("NAME2:", &raw_text, '\r', true);
|
||||
let phone_numbers: Vec<String> = ::match_multiple_value_prefix("TEL", &raw_text);
|
||||
let emails: Vec<String> = ::match_multiple_value_prefix("MAIL", &raw_text);
|
||||
let note: String = match_single_prefixed_field("MEMORY:", &raw_text, '\r', false);
|
||||
let address: String = match_single_prefixed_field("ADD:", &raw_text, '\r', true);
|
||||
let addresses: Vec<String> = if address == null { null } else { : vec![String; 1] = vec![address, ]
|
||||
};
|
||||
return AddressBookParsedResult::new(&maybe_wrap(&name), null, &pronunciation, &phone_numbers, null, &emails, null, null, ¬e, &addresses, null, null, null, null, null, null);
|
||||
}
|
||||
|
||||
fn match_multiple_value_prefix( prefix: &String, raw_text: &String) -> Vec<String> {
|
||||
let mut values: List<String> = null;
|
||||
// For now, always 3, and always trim
|
||||
{
|
||||
let mut i: i32 = 1;
|
||||
while i <= 3 {
|
||||
{
|
||||
let value: String = match_single_prefixed_field(format!("{}{}:", prefix, i), &raw_text, '\r', true);
|
||||
if value == null {
|
||||
break;
|
||||
}
|
||||
if values == null {
|
||||
// lazy init
|
||||
values = ArrayList<>::new(3);
|
||||
}
|
||||
values.add(&value);
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
if values == null {
|
||||
return null;
|
||||
}
|
||||
return values.to_array(EMPTY_STR_ARRAY);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* 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::client::result;
|
||||
|
||||
/**
|
||||
* Implements the "MECARD" address book entry format.
|
||||
*
|
||||
* Supported keys: N, SOUND, TEL, EMAIL, NOTE, ADR, BDAY, URL, plus ORG
|
||||
* Unsupported keys: TEL-AV, NICKNAME
|
||||
*
|
||||
* Except for TEL, multiple values for keys are also not supported;
|
||||
* the first one found takes precedence.
|
||||
*
|
||||
* Our understanding of the MECARD format is based on this document:
|
||||
*
|
||||
* http://www.mobicode.org.tw/files/OMIA%20Mobile%20Bar%20Code%20Standard%20v3.2.1.doc
|
||||
*
|
||||
* @author Sean Owen
|
||||
*/
|
||||
pub struct AddressBookDoCoMoResultParser {
|
||||
super: AbstractDoCoMoResultParser;
|
||||
}
|
||||
|
||||
impl AddressBookDoCoMoResultParser {
|
||||
|
||||
pub fn parse(&self, result: &Result) -> AddressBookParsedResult {
|
||||
let raw_text: String = get_massaged_text(result);
|
||||
if !raw_text.starts_with("MECARD:") {
|
||||
return null;
|
||||
}
|
||||
let raw_name: Vec<String> = match_do_co_mo_prefixed_field("N:", &raw_text);
|
||||
if raw_name == null {
|
||||
return null;
|
||||
}
|
||||
let name: String = ::parse_name(raw_name[0]);
|
||||
let pronunciation: String = match_single_do_co_mo_prefixed_field("SOUND:", &raw_text, true);
|
||||
let phone_numbers: Vec<String> = match_do_co_mo_prefixed_field("TEL:", &raw_text);
|
||||
let emails: Vec<String> = match_do_co_mo_prefixed_field("EMAIL:", &raw_text);
|
||||
let note: String = match_single_do_co_mo_prefixed_field("NOTE:", &raw_text, false);
|
||||
let addresses: Vec<String> = match_do_co_mo_prefixed_field("ADR:", &raw_text);
|
||||
let mut birthday: String = match_single_do_co_mo_prefixed_field("BDAY:", &raw_text, true);
|
||||
if !is_string_of_digits(&birthday, 8) {
|
||||
// No reason to throw out the whole card because the birthday is formatted wrong.
|
||||
birthday = null;
|
||||
}
|
||||
let urls: Vec<String> = match_do_co_mo_prefixed_field("URL:", &raw_text);
|
||||
// Although ORG may not be strictly legal in MECARD, it does exist in VCARD and we might as well
|
||||
// honor it when found in the wild.
|
||||
let org: String = match_single_do_co_mo_prefixed_field("ORG:", &raw_text, true);
|
||||
return AddressBookParsedResult::new(&maybe_wrap(&name), null, &pronunciation, &phone_numbers, null, &emails, null, null, ¬e, &addresses, null, &org, &birthday, null, &urls, null);
|
||||
}
|
||||
|
||||
fn parse_name( name: &String) -> String {
|
||||
let comma: i32 = name.index_of(',');
|
||||
if comma >= 0 {
|
||||
// Format may be last,first; switch it around
|
||||
return name.substring(comma + 1) + ' ' + name.substring(0, comma);
|
||||
}
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,201 @@
|
||||
/*
|
||||
* 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::client::result;
|
||||
|
||||
/**
|
||||
* Represents a parsed result that encodes contact information, like that in an address book
|
||||
* entry.
|
||||
*
|
||||
* @author Sean Owen
|
||||
*/
|
||||
pub struct AddressBookParsedResult {
|
||||
super: ParsedResult;
|
||||
|
||||
let names: Vec<String>;
|
||||
|
||||
let nicknames: Vec<String>;
|
||||
|
||||
let pronunciation: String;
|
||||
|
||||
let phone_numbers: Vec<String>;
|
||||
|
||||
let phone_types: Vec<String>;
|
||||
|
||||
let emails: Vec<String>;
|
||||
|
||||
let email_types: Vec<String>;
|
||||
|
||||
let instant_messenger: String;
|
||||
|
||||
let note: String;
|
||||
|
||||
let addresses: Vec<String>;
|
||||
|
||||
let address_types: Vec<String>;
|
||||
|
||||
let org: String;
|
||||
|
||||
let birthday: String;
|
||||
|
||||
let title: String;
|
||||
|
||||
let urls: Vec<String>;
|
||||
|
||||
let geo: Vec<String>;
|
||||
}
|
||||
|
||||
impl AddressBookParsedResult {
|
||||
|
||||
pub fn new( names: &Vec<String>, phone_numbers: &Vec<String>, phone_types: &Vec<String>, emails: &Vec<String>, email_types: &Vec<String>, addresses: &Vec<String>, address_types: &Vec<String>) -> AddressBookParsedResult {
|
||||
this(&names, null, null, &phone_numbers, &phone_types, &emails, &email_types, null, null, &addresses, &address_types, null, null, null, null, null);
|
||||
}
|
||||
|
||||
pub fn new( names: &Vec<String>, nicknames: &Vec<String>, pronunciation: &String, phone_numbers: &Vec<String>, phone_types: &Vec<String>, emails: &Vec<String>, email_types: &Vec<String>, instant_messenger: &String, note: &String, addresses: &Vec<String>, address_types: &Vec<String>, org: &String, birthday: &String, title: &String, urls: &Vec<String>, geo: &Vec<String>) -> AddressBookParsedResult {
|
||||
super(ParsedResultType::ADDRESSBOOK);
|
||||
if phone_numbers != null && phone_types != null && phone_numbers.len() != phone_types.len() {
|
||||
throw IllegalArgumentException::new("Phone numbers and types lengths differ");
|
||||
}
|
||||
if emails != null && email_types != null && emails.len() != email_types.len() {
|
||||
throw IllegalArgumentException::new("Emails and types lengths differ");
|
||||
}
|
||||
if addresses != null && address_types != null && addresses.len() != address_types.len() {
|
||||
throw IllegalArgumentException::new("Addresses and types lengths differ");
|
||||
}
|
||||
let .names = names;
|
||||
let .nicknames = nicknames;
|
||||
let .pronunciation = pronunciation;
|
||||
let .phoneNumbers = phone_numbers;
|
||||
let .phoneTypes = phone_types;
|
||||
let .emails = emails;
|
||||
let .emailTypes = email_types;
|
||||
let .instantMessenger = instant_messenger;
|
||||
let .note = note;
|
||||
let .addresses = addresses;
|
||||
let .addressTypes = address_types;
|
||||
let .org = org;
|
||||
let .birthday = birthday;
|
||||
let .title = title;
|
||||
let .urls = urls;
|
||||
let .geo = geo;
|
||||
}
|
||||
|
||||
pub fn get_names(&self) -> Vec<String> {
|
||||
return self.names;
|
||||
}
|
||||
|
||||
pub fn get_nicknames(&self) -> Vec<String> {
|
||||
return self.nicknames;
|
||||
}
|
||||
|
||||
/**
|
||||
* In Japanese, the name is written in kanji, which can have multiple readings. Therefore a hint
|
||||
* is often provided, called furigana, which spells the name phonetically.
|
||||
*
|
||||
* @return The pronunciation of the getNames() field, often in hiragana or katakana.
|
||||
*/
|
||||
pub fn get_pronunciation(&self) -> String {
|
||||
return self.pronunciation;
|
||||
}
|
||||
|
||||
pub fn get_phone_numbers(&self) -> Vec<String> {
|
||||
return self.phone_numbers;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return optional descriptions of the type of each phone number. It could be like "HOME", but,
|
||||
* there is no guaranteed or standard format.
|
||||
*/
|
||||
pub fn get_phone_types(&self) -> Vec<String> {
|
||||
return self.phone_types;
|
||||
}
|
||||
|
||||
pub fn get_emails(&self) -> Vec<String> {
|
||||
return self.emails;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return optional descriptions of the type of each e-mail. It could be like "WORK", but,
|
||||
* there is no guaranteed or standard format.
|
||||
*/
|
||||
pub fn get_email_types(&self) -> Vec<String> {
|
||||
return self.email_types;
|
||||
}
|
||||
|
||||
pub fn get_instant_messenger(&self) -> String {
|
||||
return self.instant_messenger;
|
||||
}
|
||||
|
||||
pub fn get_note(&self) -> String {
|
||||
return self.note;
|
||||
}
|
||||
|
||||
pub fn get_addresses(&self) -> Vec<String> {
|
||||
return self.addresses;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return optional descriptions of the type of each e-mail. It could be like "WORK", but,
|
||||
* there is no guaranteed or standard format.
|
||||
*/
|
||||
pub fn get_address_types(&self) -> Vec<String> {
|
||||
return self.address_types;
|
||||
}
|
||||
|
||||
pub fn get_title(&self) -> String {
|
||||
return self.title;
|
||||
}
|
||||
|
||||
pub fn get_org(&self) -> String {
|
||||
return self.org;
|
||||
}
|
||||
|
||||
pub fn get_u_r_ls(&self) -> Vec<String> {
|
||||
return self.urls;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return birthday formatted as yyyyMMdd (e.g. 19780917)
|
||||
*/
|
||||
pub fn get_birthday(&self) -> String {
|
||||
return self.birthday;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return a location as a latitude/longitude pair
|
||||
*/
|
||||
pub fn get_geo(&self) -> Vec<String> {
|
||||
return self.geo;
|
||||
}
|
||||
|
||||
pub fn get_display_result(&self) -> String {
|
||||
let result: StringBuilder = StringBuilder::new(100);
|
||||
maybe_append(&self.names, &result);
|
||||
maybe_append(&self.nicknames, &result);
|
||||
maybe_append(&self.pronunciation, &result);
|
||||
maybe_append(&self.title, &result);
|
||||
maybe_append(&self.org, &result);
|
||||
maybe_append(&self.addresses, &result);
|
||||
maybe_append(&self.phone_numbers, &result);
|
||||
maybe_append(&self.emails, &result);
|
||||
maybe_append(&self.instant_messenger, &result);
|
||||
maybe_append(&self.urls, &result);
|
||||
maybe_append(&self.birthday, &result);
|
||||
maybe_append(&self.geo, &result);
|
||||
maybe_append(&self.note, &result);
|
||||
return result.to_string();
|
||||
}
|
||||
}
|
||||
|
||||
78
port_src/output/zxing/client/result/bizcard_result_parser.rs
Normal file
78
port_src/output/zxing/client/result/bizcard_result_parser.rs
Normal file
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* 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::client::result;
|
||||
|
||||
/**
|
||||
* Implements the "BIZCARD" address book entry format, though this has been
|
||||
* largely reverse-engineered from examples observed in the wild -- still
|
||||
* looking for a definitive reference.
|
||||
*
|
||||
* @author Sean Owen
|
||||
*/
|
||||
pub struct BizcardResultParser {
|
||||
super: AbstractDoCoMoResultParser;
|
||||
}
|
||||
|
||||
impl BizcardResultParser {
|
||||
|
||||
// Yes, we extend AbstractDoCoMoResultParser since the format is very much
|
||||
// like the DoCoMo MECARD format, but this is not technically one of
|
||||
// DoCoMo's proposed formats
|
||||
pub fn parse(&self, result: &Result) -> AddressBookParsedResult {
|
||||
let raw_text: String = get_massaged_text(result);
|
||||
if !raw_text.starts_with("BIZCARD:") {
|
||||
return null;
|
||||
}
|
||||
let first_name: String = match_single_do_co_mo_prefixed_field("N:", &raw_text, true);
|
||||
let last_name: String = match_single_do_co_mo_prefixed_field("X:", &raw_text, true);
|
||||
let full_name: String = ::build_name(&first_name, &last_name);
|
||||
let title: String = match_single_do_co_mo_prefixed_field("T:", &raw_text, true);
|
||||
let org: String = match_single_do_co_mo_prefixed_field("C:", &raw_text, true);
|
||||
let addresses: Vec<String> = match_do_co_mo_prefixed_field("A:", &raw_text);
|
||||
let phone_number1: String = match_single_do_co_mo_prefixed_field("B:", &raw_text, true);
|
||||
let phone_number2: String = match_single_do_co_mo_prefixed_field("M:", &raw_text, true);
|
||||
let phone_number3: String = match_single_do_co_mo_prefixed_field("F:", &raw_text, true);
|
||||
let email: String = match_single_do_co_mo_prefixed_field("E:", &raw_text, true);
|
||||
return AddressBookParsedResult::new(&maybe_wrap(&full_name), null, null, &::build_phone_numbers(&phone_number1, &phone_number2, &phone_number3), null, &maybe_wrap(&email), null, null, null, &addresses, null, &org, null, &title, null, null);
|
||||
}
|
||||
|
||||
fn build_phone_numbers( number1: &String, number2: &String, number3: &String) -> Vec<String> {
|
||||
let numbers: List<String> = ArrayList<>::new(3);
|
||||
if number1 != null {
|
||||
numbers.add(&number1);
|
||||
}
|
||||
if number2 != null {
|
||||
numbers.add(&number2);
|
||||
}
|
||||
if number3 != null {
|
||||
numbers.add(&number3);
|
||||
}
|
||||
let size: i32 = numbers.size();
|
||||
if size == 0 {
|
||||
return null;
|
||||
}
|
||||
return numbers.to_array(: [Option<String>; size] = [None; size]);
|
||||
}
|
||||
|
||||
fn build_name( first_name: &String, last_name: &String) -> String {
|
||||
if first_name == null {
|
||||
return last_name;
|
||||
} else {
|
||||
return if last_name == null { first_name } else { format!("{} {}", first_name, last_name) };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* 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::client::result;
|
||||
|
||||
/**
|
||||
* @author Sean Owen
|
||||
*/
|
||||
pub struct BookmarkDoCoMoResultParser {
|
||||
super: AbstractDoCoMoResultParser;
|
||||
}
|
||||
|
||||
impl BookmarkDoCoMoResultParser {
|
||||
|
||||
pub fn parse(&self, result: &Result) -> URIParsedResult {
|
||||
let raw_text: String = result.get_text();
|
||||
if !raw_text.starts_with("MEBKM:") {
|
||||
return null;
|
||||
}
|
||||
let title: String = match_single_do_co_mo_prefixed_field("TITLE:", &raw_text, true);
|
||||
let raw_uri: Vec<String> = match_do_co_mo_prefixed_field("URL:", &raw_text);
|
||||
if raw_uri == null {
|
||||
return null;
|
||||
}
|
||||
let uri: String = raw_uri[0];
|
||||
return if URIResultParser::is_basically_valid_u_r_i(&uri) { URIParsedResult::new(&uri, &title) } else { null };
|
||||
}
|
||||
}
|
||||
|
||||
266
port_src/output/zxing/client/result/calendar_parsed_result.rs
Normal file
266
port_src/output/zxing/client/result/calendar_parsed_result.rs
Normal file
@@ -0,0 +1,266 @@
|
||||
/*
|
||||
* 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::client::result;
|
||||
|
||||
/**
|
||||
* Represents a parsed result that encodes a calendar event at a certain time, optionally
|
||||
* with attendees and a location.
|
||||
*
|
||||
* @author Sean Owen
|
||||
*/
|
||||
|
||||
const RFC2445_DURATION: Pattern = Pattern::compile("P(?:(\\d+)W)?(?:(\\d+)D)?(?:T(?:(\\d+)H)?(?:(\\d+)M)?(?:(\\d+)S)?)?");
|
||||
|
||||
const RFC2445_DURATION_FIELD_UNITS: vec![Vec<i64>; 5] = vec![// 1 week
|
||||
7 * 24 * 60 * 60 * 1000, // 1 day
|
||||
24 * 60 * 60 * 1000, // 1 hour
|
||||
60 * 60 * 1000, // 1 minute
|
||||
60 * 1000, // 1 second
|
||||
1000, ]
|
||||
;
|
||||
|
||||
const DATE_TIME: Pattern = Pattern::compile("[0-9]{8}(T[0-9]{6}Z?)?");
|
||||
pub struct CalendarParsedResult {
|
||||
super: ParsedResult;
|
||||
|
||||
let summary: String;
|
||||
|
||||
let mut start: i64;
|
||||
|
||||
let start_all_day: bool;
|
||||
|
||||
let mut end: i64;
|
||||
|
||||
let end_all_day: bool;
|
||||
|
||||
let location: String;
|
||||
|
||||
let organizer: String;
|
||||
|
||||
let attendees: Vec<String>;
|
||||
|
||||
let description: String;
|
||||
|
||||
let latitude: f64;
|
||||
|
||||
let longitude: f64;
|
||||
}
|
||||
|
||||
impl CalendarParsedResult {
|
||||
|
||||
pub fn new( summary: &String, start_string: &String, end_string: &String, duration_string: &String, location: &String, organizer: &String, attendees: &Vec<String>, description: &String, latitude: f64, longitude: f64) -> CalendarParsedResult {
|
||||
super(ParsedResultType::CALENDAR);
|
||||
let .summary = summary;
|
||||
let tryResult1 = 0;
|
||||
'try1: loop {
|
||||
{
|
||||
let .start = ::parse_date(&start_string);
|
||||
}
|
||||
break 'try1
|
||||
}
|
||||
match tryResult1 {
|
||||
catch ( pe: &ParseException) {
|
||||
throw IllegalArgumentException::new(&pe.to_string());
|
||||
} 0 => break
|
||||
}
|
||||
|
||||
if end_string == null {
|
||||
let duration_m_s: i64 = ::parse_duration_m_s(&duration_string);
|
||||
end = if duration_m_s < 0 { -1 } else { start + duration_m_s };
|
||||
} else {
|
||||
let tryResult1 = 0;
|
||||
'try1: loop {
|
||||
{
|
||||
let .end = ::parse_date(&end_string);
|
||||
}
|
||||
break 'try1
|
||||
}
|
||||
match tryResult1 {
|
||||
catch ( pe: &ParseException) {
|
||||
throw IllegalArgumentException::new(&pe.to_string());
|
||||
} 0 => break
|
||||
}
|
||||
|
||||
}
|
||||
let .startAllDay = start_string.length() == 8;
|
||||
let .endAllDay = end_string != null && end_string.length() == 8;
|
||||
let .location = location;
|
||||
let .organizer = organizer;
|
||||
let .attendees = attendees;
|
||||
let .description = description;
|
||||
let .latitude = latitude;
|
||||
let .longitude = longitude;
|
||||
}
|
||||
|
||||
pub fn get_summary(&self) -> String {
|
||||
return self.summary;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return start time
|
||||
* @deprecated use {@link #getStartTimestamp()}
|
||||
*/
|
||||
pub fn get_start(&self) -> Date {
|
||||
return Date::new(self.start);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return start time
|
||||
* @see #getEndTimestamp()
|
||||
*/
|
||||
pub fn get_start_timestamp(&self) -> i64 {
|
||||
return self.start;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if start time was specified as a whole day
|
||||
*/
|
||||
pub fn is_start_all_day(&self) -> bool {
|
||||
return self.start_all_day;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return event end {@link Date}, or {@code null} if event has no duration
|
||||
* @deprecated use {@link #getEndTimestamp()}
|
||||
*/
|
||||
pub fn get_end(&self) -> Date {
|
||||
return if self.end < 0 { null } else { Date::new(self.end) };
|
||||
}
|
||||
|
||||
/**
|
||||
* @return event end {@link Date}, or -1 if event has no duration
|
||||
* @see #getStartTimestamp()
|
||||
*/
|
||||
pub fn get_end_timestamp(&self) -> i64 {
|
||||
return self.end;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if end time was specified as a whole day
|
||||
*/
|
||||
pub fn is_end_all_day(&self) -> bool {
|
||||
return self.end_all_day;
|
||||
}
|
||||
|
||||
pub fn get_location(&self) -> String {
|
||||
return self.location;
|
||||
}
|
||||
|
||||
pub fn get_organizer(&self) -> String {
|
||||
return self.organizer;
|
||||
}
|
||||
|
||||
pub fn get_attendees(&self) -> Vec<String> {
|
||||
return self.attendees;
|
||||
}
|
||||
|
||||
pub fn get_description(&self) -> String {
|
||||
return self.description;
|
||||
}
|
||||
|
||||
pub fn get_latitude(&self) -> f64 {
|
||||
return self.latitude;
|
||||
}
|
||||
|
||||
pub fn get_longitude(&self) -> f64 {
|
||||
return self.longitude;
|
||||
}
|
||||
|
||||
pub fn get_display_result(&self) -> String {
|
||||
let result: StringBuilder = StringBuilder::new(100);
|
||||
maybe_append(&self.summary, &result);
|
||||
maybe_append(&::format(self.start_all_day, self.start), &result);
|
||||
maybe_append(&::format(self.end_all_day, self.end), &result);
|
||||
maybe_append(&self.location, &result);
|
||||
maybe_append(&self.organizer, &result);
|
||||
maybe_append(&self.attendees, &result);
|
||||
maybe_append(&self.description, &result);
|
||||
return result.to_string();
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a string as a date. RFC 2445 allows the start and end fields to be of type DATE (e.g. 20081021)
|
||||
* or DATE-TIME (e.g. 20081021T123000 for local time, or 20081021T123000Z for UTC).
|
||||
*
|
||||
* @param when The string to parse
|
||||
* @throws ParseException if not able to parse as a date
|
||||
*/
|
||||
fn parse_date( when: &String) -> /* throws ParseException */Result<i64, Rc<Exception>> {
|
||||
if !DATE_TIME::matcher(&when)::matches() {
|
||||
throw ParseException::new(&when, 0);
|
||||
}
|
||||
if when.length() == 8 {
|
||||
// Show only year/month/day
|
||||
let format: DateFormat = SimpleDateFormat::new("yyyyMMdd", Locale::ENGLISH);
|
||||
// For dates without a time, for purposes of interacting with Android, the resulting timestamp
|
||||
// needs to be midnight of that day in GMT. See:
|
||||
// http://code.google.com/p/android/issues/detail?id=8330
|
||||
format.set_time_zone(&TimeZone::get_time_zone("GMT"));
|
||||
return Ok(format.parse(&when).get_time());
|
||||
}
|
||||
// The when string can be local time, or UTC if it ends with a Z
|
||||
if when.length() == 16 && when.char_at(15) == 'Z' {
|
||||
let mut milliseconds: i64 = ::parse_date_time_string(&when.substring(0, 15));
|
||||
let calendar: Calendar = GregorianCalendar::new();
|
||||
// Account for time zone difference
|
||||
milliseconds += calendar.get(Calendar::ZONE_OFFSET);
|
||||
// Might need to correct for daylight savings time, but use target time since
|
||||
// now might be in DST but not then, or vice versa
|
||||
calendar.set_time(Date::new(milliseconds));
|
||||
return Ok(milliseconds + calendar.get(Calendar::DST_OFFSET));
|
||||
}
|
||||
return Ok(::parse_date_time_string(&when));
|
||||
}
|
||||
|
||||
fn format( all_day: bool, date: i64) -> String {
|
||||
if date < 0 {
|
||||
return null;
|
||||
}
|
||||
let format: DateFormat = if all_day { DateFormat::get_date_instance(DateFormat::MEDIUM) } else { DateFormat::get_date_time_instance(DateFormat::MEDIUM, DateFormat::MEDIUM) };
|
||||
return format.format(date);
|
||||
}
|
||||
|
||||
fn parse_duration_m_s( duration_string: &CharSequence) -> i64 {
|
||||
if duration_string == null {
|
||||
return -1;
|
||||
}
|
||||
let m: Matcher = RFC2445_DURATION::matcher(&duration_string);
|
||||
if !m.matches() {
|
||||
return -1;
|
||||
}
|
||||
let duration_m_s: i64 = 0;
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < RFC2445_DURATION_FIELD_UNITS.len() {
|
||||
{
|
||||
let field_value: String = m.group(i + 1);
|
||||
if field_value != null {
|
||||
duration_m_s += RFC2445_DURATION_FIELD_UNITS[i] * Integer::parse_int(&field_value);
|
||||
}
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
return duration_m_s;
|
||||
}
|
||||
|
||||
fn parse_date_time_string( date_time_string: &String) -> /* throws ParseException */Result<i64, Rc<Exception>> {
|
||||
let format: DateFormat = SimpleDateFormat::new("yyyyMMdd'T'HHmmss", Locale::ENGLISH);
|
||||
return Ok(format.parse(&date_time_string).get_time());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* 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::client::result;
|
||||
|
||||
/**
|
||||
* Represents a parsed result that encodes an email message including recipients, subject
|
||||
* and body text.
|
||||
*
|
||||
* @author Sean Owen
|
||||
*/
|
||||
pub struct EmailAddressParsedResult {
|
||||
super: ParsedResult;
|
||||
|
||||
let tos: Vec<String>;
|
||||
|
||||
let ccs: Vec<String>;
|
||||
|
||||
let bccs: Vec<String>;
|
||||
|
||||
let subject: String;
|
||||
|
||||
let body: String;
|
||||
}
|
||||
|
||||
impl EmailAddressParsedResult {
|
||||
|
||||
fn new( to: &String) -> EmailAddressParsedResult {
|
||||
this( : vec![String; 1] = vec![to, ]
|
||||
, null, null, null, null);
|
||||
}
|
||||
|
||||
fn new( tos: &Vec<String>, ccs: &Vec<String>, bccs: &Vec<String>, subject: &String, body: &String) -> EmailAddressParsedResult {
|
||||
super(ParsedResultType::EMAIL_ADDRESS);
|
||||
let .tos = tos;
|
||||
let .ccs = ccs;
|
||||
let .bccs = bccs;
|
||||
let .subject = subject;
|
||||
let .body = body;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return first elements of {@link #getTos()} or {@code null} if none
|
||||
* @deprecated use {@link #getTos()}
|
||||
*/
|
||||
pub fn get_email_address(&self) -> String {
|
||||
return if self.tos == null || self.tos.len() == 0 { null } else { self.tos[0] };
|
||||
}
|
||||
|
||||
pub fn get_tos(&self) -> Vec<String> {
|
||||
return self.tos;
|
||||
}
|
||||
|
||||
pub fn get_c_cs(&self) -> Vec<String> {
|
||||
return self.ccs;
|
||||
}
|
||||
|
||||
pub fn get_b_c_cs(&self) -> Vec<String> {
|
||||
return self.bccs;
|
||||
}
|
||||
|
||||
pub fn get_subject(&self) -> String {
|
||||
return self.subject;
|
||||
}
|
||||
|
||||
pub fn get_body(&self) -> String {
|
||||
return self.body;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return "mailto:"
|
||||
* @deprecated without replacement
|
||||
*/
|
||||
pub fn get_mailto_u_r_i(&self) -> String {
|
||||
return "mailto:";
|
||||
}
|
||||
|
||||
pub fn get_display_result(&self) -> String {
|
||||
let result: StringBuilder = StringBuilder::new(30);
|
||||
maybe_append(&self.tos, &result);
|
||||
maybe_append(&self.ccs, &result);
|
||||
maybe_append(&self.bccs, &result);
|
||||
maybe_append(&self.subject, &result);
|
||||
maybe_append(&self.body, &result);
|
||||
return result.to_string();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* 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::client::result;
|
||||
|
||||
/**
|
||||
* Represents a result that encodes an e-mail address, either as a plain address
|
||||
* like "joe@example.org" or a mailto: URL like "mailto:joe@example.org".
|
||||
*
|
||||
* @author Sean Owen
|
||||
*/
|
||||
|
||||
const COMMA: Pattern = Pattern::compile(",");
|
||||
pub struct EmailAddressResultParser {
|
||||
super: ResultParser;
|
||||
}
|
||||
|
||||
impl EmailAddressResultParser {
|
||||
|
||||
pub fn parse(&self, result: &Result) -> EmailAddressParsedResult {
|
||||
let raw_text: String = get_massaged_text(result);
|
||||
if raw_text.starts_with("mailto:") || raw_text.starts_with("MAILTO:") {
|
||||
// If it starts with mailto:, assume it is definitely trying to be an email address
|
||||
let host_email: String = raw_text.substring(7);
|
||||
let query_start: i32 = host_email.index_of('?');
|
||||
if query_start >= 0 {
|
||||
host_email = host_email.substring(0, query_start);
|
||||
}
|
||||
let tryResult1 = 0;
|
||||
'try1: loop {
|
||||
{
|
||||
host_email = url_decode(&host_email);
|
||||
}
|
||||
break 'try1
|
||||
}
|
||||
match tryResult1 {
|
||||
catch ( iae: &IllegalArgumentException) {
|
||||
return null;
|
||||
} 0 => break
|
||||
}
|
||||
|
||||
let mut tos: Vec<String> = null;
|
||||
if !host_email.is_empty() {
|
||||
tos = COMMA::split(&host_email);
|
||||
}
|
||||
let name_values: Map<String, String> = parse_name_value_pairs(&raw_text);
|
||||
let mut ccs: Vec<String> = null;
|
||||
let mut bccs: Vec<String> = null;
|
||||
let mut subject: String = null;
|
||||
let mut body: String = null;
|
||||
if name_values != null {
|
||||
if tos == null {
|
||||
let tos_string: String = name_values.get("to");
|
||||
if tos_string != null {
|
||||
tos = COMMA::split(&tos_string);
|
||||
}
|
||||
}
|
||||
let cc_string: String = name_values.get("cc");
|
||||
if cc_string != null {
|
||||
ccs = COMMA::split(&cc_string);
|
||||
}
|
||||
let bcc_string: String = name_values.get("bcc");
|
||||
if bcc_string != null {
|
||||
bccs = COMMA::split(&bcc_string);
|
||||
}
|
||||
subject = name_values.get("subject");
|
||||
body = name_values.get("body");
|
||||
}
|
||||
return EmailAddressParsedResult::new(&tos, &ccs, &bccs, &subject, &body);
|
||||
} else {
|
||||
if !EmailDoCoMoResultParser::is_basically_valid_email_address(&raw_text) {
|
||||
return null;
|
||||
}
|
||||
return EmailAddressParsedResult::new(&raw_text);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* 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::client::result;
|
||||
|
||||
/**
|
||||
* Implements the "MATMSG" email message entry format.
|
||||
*
|
||||
* Supported keys: TO, SUB, BODY
|
||||
*
|
||||
* @author Sean Owen
|
||||
*/
|
||||
|
||||
const ATEXT_ALPHANUMERIC: Pattern = Pattern::compile("[a-zA-Z0-9@.!#$%&'*+\\-/=?^_`{|}~]+");
|
||||
pub struct EmailDoCoMoResultParser {
|
||||
super: AbstractDoCoMoResultParser;
|
||||
}
|
||||
|
||||
impl EmailDoCoMoResultParser {
|
||||
|
||||
pub fn parse(&self, result: &Result) -> EmailAddressParsedResult {
|
||||
let raw_text: String = get_massaged_text(result);
|
||||
if !raw_text.starts_with("MATMSG:") {
|
||||
return null;
|
||||
}
|
||||
let tos: Vec<String> = match_do_co_mo_prefixed_field("TO:", &raw_text);
|
||||
if tos == null {
|
||||
return null;
|
||||
}
|
||||
for let to: String in tos {
|
||||
if !::is_basically_valid_email_address(&to) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
let subject: String = match_single_do_co_mo_prefixed_field("SUB:", &raw_text, false);
|
||||
let body: String = match_single_do_co_mo_prefixed_field("BODY:", &raw_text, false);
|
||||
return EmailAddressParsedResult::new(&tos, null, null, &subject, &body);
|
||||
}
|
||||
|
||||
/**
|
||||
* This implements only the most basic checking for an email address's validity -- that it contains
|
||||
* an '@' and contains no characters disallowed by RFC 2822. This is an overly lenient definition of
|
||||
* validity. We want to generally be lenient here since this class is only intended to encapsulate what's
|
||||
* in a barcode, not "judge" it.
|
||||
*/
|
||||
fn is_basically_valid_email_address( email: &String) -> bool {
|
||||
return email != null && ATEXT_ALPHANUMERIC::matcher(&email)::matches() && email.index_of('@') >= 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,174 @@
|
||||
/*
|
||||
* Copyright (C) 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::client::result;
|
||||
|
||||
/**
|
||||
* Represents a parsed result that encodes extended product information as encoded
|
||||
* by the RSS format, like weight, price, dates, etc.
|
||||
*
|
||||
* @author Antonio Manuel Benjumea Conde, Servinform, S.A.
|
||||
* @author AgustÃn Delgado, Servinform, S.A.
|
||||
*/
|
||||
|
||||
const KILOGRAM: &'static str = "KG";
|
||||
|
||||
const POUND: &'static str = "LB";
|
||||
pub struct ExpandedProductParsedResult {
|
||||
super: ParsedResult;
|
||||
|
||||
let raw_text: String;
|
||||
|
||||
let product_i_d: String;
|
||||
|
||||
let sscc: String;
|
||||
|
||||
let lot_number: String;
|
||||
|
||||
let production_date: String;
|
||||
|
||||
let packaging_date: String;
|
||||
|
||||
let best_before_date: String;
|
||||
|
||||
let expiration_date: String;
|
||||
|
||||
let weight: String;
|
||||
|
||||
let weight_type: String;
|
||||
|
||||
let weight_increment: String;
|
||||
|
||||
let price: String;
|
||||
|
||||
let price_increment: String;
|
||||
|
||||
let price_currency: String;
|
||||
|
||||
// For AIS that not exist in this object
|
||||
let uncommon_a_is: Map<String, String>;
|
||||
}
|
||||
|
||||
impl ExpandedProductParsedResult {
|
||||
|
||||
pub fn new( raw_text: &String, product_i_d: &String, sscc: &String, lot_number: &String, production_date: &String, packaging_date: &String, best_before_date: &String, expiration_date: &String, weight: &String, weight_type: &String, weight_increment: &String, price: &String, price_increment: &String, price_currency: &String, uncommon_a_is: &Map<String, String>) -> ExpandedProductParsedResult {
|
||||
super(ParsedResultType::PRODUCT);
|
||||
let .rawText = raw_text;
|
||||
let .productID = product_i_d;
|
||||
let .sscc = sscc;
|
||||
let .lotNumber = lot_number;
|
||||
let .productionDate = production_date;
|
||||
let .packagingDate = packaging_date;
|
||||
let .bestBeforeDate = best_before_date;
|
||||
let .expirationDate = expiration_date;
|
||||
let .weight = weight;
|
||||
let .weightType = weight_type;
|
||||
let .weightIncrement = weight_increment;
|
||||
let .price = price;
|
||||
let .priceIncrement = price_increment;
|
||||
let .priceCurrency = price_currency;
|
||||
let .uncommonAIs = uncommon_a_is;
|
||||
}
|
||||
|
||||
pub fn equals(&self, o: &Object) -> bool {
|
||||
if !(o instanceof ExpandedProductParsedResult) {
|
||||
return false;
|
||||
}
|
||||
let other: ExpandedProductParsedResult = o as ExpandedProductParsedResult;
|
||||
return Objects::equals(&self.product_i_d, other.productID) && Objects::equals(&self.sscc, other.sscc) && Objects::equals(&self.lot_number, other.lotNumber) && Objects::equals(&self.production_date, other.productionDate) && Objects::equals(&self.best_before_date, other.bestBeforeDate) && Objects::equals(&self.expiration_date, other.expirationDate) && Objects::equals(&self.weight, other.weight) && Objects::equals(&self.weight_type, other.weightType) && Objects::equals(&self.weight_increment, other.weightIncrement) && Objects::equals(&self.price, other.price) && Objects::equals(&self.price_increment, other.priceIncrement) && Objects::equals(&self.price_currency, other.priceCurrency) && Objects::equals(&self.uncommon_a_is, other.uncommonAIs);
|
||||
}
|
||||
|
||||
pub fn hash_code(&self) -> i32 {
|
||||
let mut hash: i32 = Objects::hash_code(&self.product_i_d);
|
||||
hash ^= Objects::hash_code(&self.sscc);
|
||||
hash ^= Objects::hash_code(&self.lot_number);
|
||||
hash ^= Objects::hash_code(&self.production_date);
|
||||
hash ^= Objects::hash_code(&self.best_before_date);
|
||||
hash ^= Objects::hash_code(&self.expiration_date);
|
||||
hash ^= Objects::hash_code(&self.weight);
|
||||
hash ^= Objects::hash_code(&self.weight_type);
|
||||
hash ^= Objects::hash_code(&self.weight_increment);
|
||||
hash ^= Objects::hash_code(&self.price);
|
||||
hash ^= Objects::hash_code(&self.price_increment);
|
||||
hash ^= Objects::hash_code(&self.price_currency);
|
||||
hash ^= Objects::hash_code(&self.uncommon_a_is);
|
||||
return hash;
|
||||
}
|
||||
|
||||
pub fn get_raw_text(&self) -> String {
|
||||
return self.raw_text;
|
||||
}
|
||||
|
||||
pub fn get_product_i_d(&self) -> String {
|
||||
return self.product_i_d;
|
||||
}
|
||||
|
||||
pub fn get_sscc(&self) -> String {
|
||||
return self.sscc;
|
||||
}
|
||||
|
||||
pub fn get_lot_number(&self) -> String {
|
||||
return self.lot_number;
|
||||
}
|
||||
|
||||
pub fn get_production_date(&self) -> String {
|
||||
return self.production_date;
|
||||
}
|
||||
|
||||
pub fn get_packaging_date(&self) -> String {
|
||||
return self.packaging_date;
|
||||
}
|
||||
|
||||
pub fn get_best_before_date(&self) -> String {
|
||||
return self.best_before_date;
|
||||
}
|
||||
|
||||
pub fn get_expiration_date(&self) -> String {
|
||||
return self.expiration_date;
|
||||
}
|
||||
|
||||
pub fn get_weight(&self) -> String {
|
||||
return self.weight;
|
||||
}
|
||||
|
||||
pub fn get_weight_type(&self) -> String {
|
||||
return self.weight_type;
|
||||
}
|
||||
|
||||
pub fn get_weight_increment(&self) -> String {
|
||||
return self.weight_increment;
|
||||
}
|
||||
|
||||
pub fn get_price(&self) -> String {
|
||||
return self.price;
|
||||
}
|
||||
|
||||
pub fn get_price_increment(&self) -> String {
|
||||
return self.price_increment;
|
||||
}
|
||||
|
||||
pub fn get_price_currency(&self) -> String {
|
||||
return self.price_currency;
|
||||
}
|
||||
|
||||
pub fn get_uncommon_a_is(&self) -> Map<String, String> {
|
||||
return self.uncommon_a_is;
|
||||
}
|
||||
|
||||
pub fn get_display_result(&self) -> String {
|
||||
return String::value_of(&self.raw_text);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,264 @@
|
||||
/*
|
||||
* Copyright (C) 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::client::result;
|
||||
|
||||
/**
|
||||
* Parses strings of digits that represent a RSS Extended code.
|
||||
*
|
||||
* @author Antonio Manuel Benjumea Conde, Servinform, S.A.
|
||||
* @author AgustÃn Delgado, Servinform, S.A.
|
||||
*/
|
||||
pub struct ExpandedProductResultParser {
|
||||
super: ResultParser;
|
||||
}
|
||||
|
||||
impl ExpandedProductResultParser {
|
||||
|
||||
pub fn parse(&self, result: &Result) -> ExpandedProductParsedResult {
|
||||
let format: BarcodeFormat = result.get_barcode_format();
|
||||
if format != BarcodeFormat::RSS_EXPANDED {
|
||||
// ExtendedProductParsedResult NOT created. Not a RSS Expanded barcode
|
||||
return null;
|
||||
}
|
||||
let raw_text: String = get_massaged_text(result);
|
||||
let product_i_d: String = null;
|
||||
let mut sscc: String = null;
|
||||
let lot_number: String = null;
|
||||
let production_date: String = null;
|
||||
let packaging_date: String = null;
|
||||
let best_before_date: String = null;
|
||||
let expiration_date: String = null;
|
||||
let mut weight: String = null;
|
||||
let weight_type: String = null;
|
||||
let weight_increment: String = null;
|
||||
let mut price: String = null;
|
||||
let price_increment: String = null;
|
||||
let price_currency: String = null;
|
||||
let uncommon_a_is: Map<String, String> = HashMap<>::new();
|
||||
let mut i: i32 = 0;
|
||||
while i < raw_text.length() {
|
||||
let ai: String = ::find_a_ivalue(i, &raw_text);
|
||||
if ai == null {
|
||||
// ExtendedProductParsedResult NOT created. Not match with RSS Expanded pattern
|
||||
return null;
|
||||
}
|
||||
i += ai.length() + 2;
|
||||
let value: String = ::find_value(i, &raw_text);
|
||||
i += value.length();
|
||||
match ai {
|
||||
"00" =>
|
||||
{
|
||||
sscc = value;
|
||||
break;
|
||||
}
|
||||
"01" =>
|
||||
{
|
||||
product_i_d = value;
|
||||
break;
|
||||
}
|
||||
"10" =>
|
||||
{
|
||||
lot_number = value;
|
||||
break;
|
||||
}
|
||||
"11" =>
|
||||
{
|
||||
production_date = value;
|
||||
break;
|
||||
}
|
||||
"13" =>
|
||||
{
|
||||
packaging_date = value;
|
||||
break;
|
||||
}
|
||||
"15" =>
|
||||
{
|
||||
best_before_date = value;
|
||||
break;
|
||||
}
|
||||
"17" =>
|
||||
{
|
||||
expiration_date = value;
|
||||
break;
|
||||
}
|
||||
"3100" =>
|
||||
{
|
||||
}
|
||||
"3101" =>
|
||||
{
|
||||
}
|
||||
"3102" =>
|
||||
{
|
||||
}
|
||||
"3103" =>
|
||||
{
|
||||
}
|
||||
"3104" =>
|
||||
{
|
||||
}
|
||||
"3105" =>
|
||||
{
|
||||
}
|
||||
"3106" =>
|
||||
{
|
||||
}
|
||||
"3107" =>
|
||||
{
|
||||
}
|
||||
"3108" =>
|
||||
{
|
||||
}
|
||||
"3109" =>
|
||||
{
|
||||
weight = value;
|
||||
weight_type = ExpandedProductParsedResult::KILOGRAM;
|
||||
weight_increment = ai.substring(3);
|
||||
break;
|
||||
}
|
||||
"3200" =>
|
||||
{
|
||||
}
|
||||
"3201" =>
|
||||
{
|
||||
}
|
||||
"3202" =>
|
||||
{
|
||||
}
|
||||
"3203" =>
|
||||
{
|
||||
}
|
||||
"3204" =>
|
||||
{
|
||||
}
|
||||
"3205" =>
|
||||
{
|
||||
}
|
||||
"3206" =>
|
||||
{
|
||||
}
|
||||
"3207" =>
|
||||
{
|
||||
}
|
||||
"3208" =>
|
||||
{
|
||||
}
|
||||
"3209" =>
|
||||
{
|
||||
weight = value;
|
||||
weight_type = ExpandedProductParsedResult::POUND;
|
||||
weight_increment = ai.substring(3);
|
||||
break;
|
||||
}
|
||||
"3920" =>
|
||||
{
|
||||
}
|
||||
"3921" =>
|
||||
{
|
||||
}
|
||||
"3922" =>
|
||||
{
|
||||
}
|
||||
"3923" =>
|
||||
{
|
||||
price = value;
|
||||
price_increment = ai.substring(3);
|
||||
break;
|
||||
}
|
||||
"3930" =>
|
||||
{
|
||||
}
|
||||
"3931" =>
|
||||
{
|
||||
}
|
||||
"3932" =>
|
||||
{
|
||||
}
|
||||
"3933" =>
|
||||
{
|
||||
if value.length() < 4 {
|
||||
// ExtendedProductParsedResult NOT created. Not match with RSS Expanded pattern
|
||||
return null;
|
||||
}
|
||||
price = value.substring(3);
|
||||
price_currency = value.substring(0, 3);
|
||||
price_increment = ai.substring(3);
|
||||
break;
|
||||
}
|
||||
_ =>
|
||||
{
|
||||
// No match with common AIs
|
||||
uncommon_a_is.put(&ai, &value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return ExpandedProductParsedResult::new(&raw_text, &product_i_d, &sscc, &lot_number, &production_date, &packaging_date, &best_before_date, &expiration_date, &weight, &weight_type, &weight_increment, &price, &price_increment, &price_currency, &uncommon_a_is);
|
||||
}
|
||||
|
||||
fn find_a_ivalue( i: i32, raw_text: &String) -> String {
|
||||
let c: char = raw_text.char_at(i);
|
||||
// First character must be a open parenthesis.If not, ERROR
|
||||
if c != '(' {
|
||||
return null;
|
||||
}
|
||||
let raw_text_aux: CharSequence = raw_text.substring(i + 1);
|
||||
let buf: StringBuilder = StringBuilder::new();
|
||||
{
|
||||
let mut index: i32 = 0;
|
||||
while index < raw_text_aux.length() {
|
||||
{
|
||||
let current_char: char = raw_text_aux.char_at(index);
|
||||
if current_char == ')' {
|
||||
return buf.to_string();
|
||||
}
|
||||
if current_char < '0' || current_char > '9' {
|
||||
return null;
|
||||
}
|
||||
buf.append(current_char);
|
||||
}
|
||||
index += 1;
|
||||
}
|
||||
}
|
||||
|
||||
return buf.to_string();
|
||||
}
|
||||
|
||||
fn find_value( i: i32, raw_text: &String) -> String {
|
||||
let buf: StringBuilder = StringBuilder::new();
|
||||
let raw_text_aux: String = raw_text.substring(i);
|
||||
{
|
||||
let mut index: i32 = 0;
|
||||
while index < raw_text_aux.length() {
|
||||
{
|
||||
let c: char = raw_text_aux.char_at(index);
|
||||
if c == '(' {
|
||||
// with the iteration
|
||||
if ::find_a_ivalue(index, &raw_text_aux) != null {
|
||||
break;
|
||||
}
|
||||
buf.append('(');
|
||||
} else {
|
||||
buf.append(c);
|
||||
}
|
||||
}
|
||||
index += 1;
|
||||
}
|
||||
}
|
||||
|
||||
return buf.to_string();
|
||||
}
|
||||
}
|
||||
|
||||
109
port_src/output/zxing/client/result/geo_parsed_result.rs
Normal file
109
port_src/output/zxing/client/result/geo_parsed_result.rs
Normal file
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* 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::client::result;
|
||||
|
||||
/**
|
||||
* Represents a parsed result that encodes a geographic coordinate, with latitude,
|
||||
* longitude and altitude.
|
||||
*
|
||||
* @author Sean Owen
|
||||
*/
|
||||
pub struct GeoParsedResult {
|
||||
super: ParsedResult;
|
||||
|
||||
let latitude: f64;
|
||||
|
||||
let longitude: f64;
|
||||
|
||||
let altitude: f64;
|
||||
|
||||
let query: String;
|
||||
}
|
||||
|
||||
impl GeoParsedResult {
|
||||
|
||||
fn new( latitude: f64, longitude: f64, altitude: f64, query: &String) -> GeoParsedResult {
|
||||
super(ParsedResultType::GEO);
|
||||
let .latitude = latitude;
|
||||
let .longitude = longitude;
|
||||
let .altitude = altitude;
|
||||
let .query = query;
|
||||
}
|
||||
|
||||
pub fn get_geo_u_r_i(&self) -> String {
|
||||
let result: StringBuilder = StringBuilder::new();
|
||||
result.append("geo:");
|
||||
result.append(self.latitude);
|
||||
result.append(',');
|
||||
result.append(self.longitude);
|
||||
if self.altitude > 0.0 {
|
||||
result.append(',');
|
||||
result.append(self.altitude);
|
||||
}
|
||||
if self.query != null {
|
||||
result.append('?');
|
||||
result.append(&self.query);
|
||||
}
|
||||
return result.to_string();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return latitude in degrees
|
||||
*/
|
||||
pub fn get_latitude(&self) -> f64 {
|
||||
return self.latitude;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return longitude in degrees
|
||||
*/
|
||||
pub fn get_longitude(&self) -> f64 {
|
||||
return self.longitude;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return altitude in meters. If not specified, in the geo URI, returns 0.0
|
||||
*/
|
||||
pub fn get_altitude(&self) -> f64 {
|
||||
return self.altitude;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return query string associated with geo URI or null if none exists
|
||||
*/
|
||||
pub fn get_query(&self) -> String {
|
||||
return self.query;
|
||||
}
|
||||
|
||||
pub fn get_display_result(&self) -> String {
|
||||
let result: StringBuilder = StringBuilder::new(20);
|
||||
result.append(self.latitude);
|
||||
result.append(", ");
|
||||
result.append(self.longitude);
|
||||
if self.altitude > 0.0 {
|
||||
result.append(", ");
|
||||
result.append(self.altitude);
|
||||
result.append('m');
|
||||
}
|
||||
if self.query != null {
|
||||
result.append(" (");
|
||||
result.append(&self.query);
|
||||
result.append(')');
|
||||
}
|
||||
return result.to_string();
|
||||
}
|
||||
}
|
||||
|
||||
75
port_src/output/zxing/client/result/geo_result_parser.rs
Normal file
75
port_src/output/zxing/client/result/geo_result_parser.rs
Normal file
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* 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::client::result;
|
||||
|
||||
/**
|
||||
* Parses a "geo:" URI result, which specifies a location on the surface of
|
||||
* the Earth as well as an optional altitude above the surface. See
|
||||
* <a href="http://tools.ietf.org/html/draft-mayrhofer-geo-uri-00">
|
||||
* http://tools.ietf.org/html/draft-mayrhofer-geo-uri-00</a>.
|
||||
*
|
||||
* @author Sean Owen
|
||||
*/
|
||||
|
||||
const GEO_URL_PATTERN: Pattern = Pattern::compile("geo:([\\-0-9.]+),([\\-0-9.]+)(?:,([\\-0-9.]+))?(?:\\?(.*))?", Pattern::CASE_INSENSITIVE);
|
||||
pub struct GeoResultParser {
|
||||
super: ResultParser;
|
||||
}
|
||||
|
||||
impl GeoResultParser {
|
||||
|
||||
pub fn parse(&self, result: &Result) -> GeoParsedResult {
|
||||
let raw_text: CharSequence = get_massaged_text(result);
|
||||
let matcher: Matcher = GEO_URL_PATTERN::matcher(&raw_text);
|
||||
if !matcher.matches() {
|
||||
return null;
|
||||
}
|
||||
let query: String = matcher.group(4);
|
||||
let mut latitude: f64;
|
||||
let mut longitude: f64;
|
||||
let mut altitude: f64;
|
||||
let tryResult1 = 0;
|
||||
'try1: loop {
|
||||
{
|
||||
latitude = Double::parse_double(&matcher.group(1));
|
||||
if latitude > 90.0 || latitude < -90.0 {
|
||||
return null;
|
||||
}
|
||||
longitude = Double::parse_double(&matcher.group(2));
|
||||
if longitude > 180.0 || longitude < -180.0 {
|
||||
return null;
|
||||
}
|
||||
if matcher.group(3) == null {
|
||||
altitude = 0.0;
|
||||
} else {
|
||||
altitude = Double::parse_double(&matcher.group(3));
|
||||
if altitude < 0.0 {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
break 'try1
|
||||
}
|
||||
match tryResult1 {
|
||||
catch ( ignored: &NumberFormatException) {
|
||||
return null;
|
||||
} 0 => break
|
||||
}
|
||||
|
||||
return GeoParsedResult::new(latitude, longitude, altitude, &query);
|
||||
}
|
||||
}
|
||||
|
||||
44
port_src/output/zxing/client/result/i_s_b_n_parsed_result.rs
Normal file
44
port_src/output/zxing/client/result/i_s_b_n_parsed_result.rs
Normal file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* 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::client::result;
|
||||
|
||||
/**
|
||||
* Represents a parsed result that encodes a product ISBN number.
|
||||
*
|
||||
* @author jbreiden@google.com (Jeff Breidenbach)
|
||||
*/
|
||||
pub struct ISBNParsedResult {
|
||||
super: ParsedResult;
|
||||
|
||||
let isbn: String;
|
||||
}
|
||||
|
||||
impl ISBNParsedResult {
|
||||
|
||||
fn new( isbn: &String) -> ISBNParsedResult {
|
||||
super(ParsedResultType::ISBN);
|
||||
let .isbn = isbn;
|
||||
}
|
||||
|
||||
pub fn get_i_s_b_n(&self) -> String {
|
||||
return self.isbn;
|
||||
}
|
||||
|
||||
pub fn get_display_result(&self) -> String {
|
||||
return self.isbn;
|
||||
}
|
||||
}
|
||||
|
||||
48
port_src/output/zxing/client/result/i_s_b_n_result_parser.rs
Normal file
48
port_src/output/zxing/client/result/i_s_b_n_result_parser.rs
Normal file
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* 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::client::result;
|
||||
|
||||
/**
|
||||
* Parses strings of digits that represent a ISBN.
|
||||
*
|
||||
* @author jbreiden@google.com (Jeff Breidenbach)
|
||||
*/
|
||||
pub struct ISBNResultParser {
|
||||
super: ResultParser;
|
||||
}
|
||||
|
||||
impl ISBNResultParser {
|
||||
|
||||
/**
|
||||
* See <a href="http://www.bisg.org/isbn-13/for.dummies.html">ISBN-13 For Dummies</a>
|
||||
*/
|
||||
pub fn parse(&self, result: &Result) -> ISBNParsedResult {
|
||||
let format: BarcodeFormat = result.get_barcode_format();
|
||||
if format != BarcodeFormat::EAN_13 {
|
||||
return null;
|
||||
}
|
||||
let raw_text: String = get_massaged_text(result);
|
||||
let length: i32 = raw_text.length();
|
||||
if length != 13 {
|
||||
return null;
|
||||
}
|
||||
if !raw_text.starts_with("978") && !raw_text.starts_with("979") {
|
||||
return null;
|
||||
}
|
||||
return ISBNParsedResult::new(&raw_text);
|
||||
}
|
||||
}
|
||||
|
||||
68
port_src/output/zxing/client/result/parsed_result.rs
Normal file
68
port_src/output/zxing/client/result/parsed_result.rs
Normal file
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* 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::client::result;
|
||||
|
||||
/**
|
||||
* <p>Abstract class representing the result of decoding a barcode, as more than
|
||||
* a String -- as some type of structured data. This might be a subclass which represents
|
||||
* a URL, or an e-mail address. {@link ResultParser#parseResult(com.google.zxing.Result)} will turn a raw
|
||||
* decoded string into the most appropriate type of structured representation.</p>
|
||||
*
|
||||
* <p>Thanks to Jeff Griffin for proposing rewrite of these classes that relies less
|
||||
* on exception-based mechanisms during parsing.</p>
|
||||
*
|
||||
* @author Sean Owen
|
||||
*/
|
||||
pub struct ParsedResult {
|
||||
|
||||
let type: ParsedResultType;
|
||||
}
|
||||
|
||||
impl ParsedResult {
|
||||
|
||||
pub fn new( type: &ParsedResultType) -> ParsedResult {
|
||||
let .type = type;
|
||||
}
|
||||
|
||||
pub fn get_type(&self) -> ParsedResultType {
|
||||
return self.type;
|
||||
}
|
||||
|
||||
pub fn get_display_result(&self) -> String ;
|
||||
|
||||
pub fn to_string(&self) -> String {
|
||||
return self.get_display_result();
|
||||
}
|
||||
|
||||
pub fn maybe_append( value: &String, result: &StringBuilder) {
|
||||
if value != null && !value.is_empty() {
|
||||
// Don't add a newline before the first value
|
||||
if result.length() > 0 {
|
||||
result.append('\n');
|
||||
}
|
||||
result.append(&value);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn maybe_append( values: &Vec<String>, result: &StringBuilder) {
|
||||
if values != null {
|
||||
for let value: String in values {
|
||||
::maybe_append(&value, &result);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
27
port_src/output/zxing/client/result/parsed_result_type.rs
Normal file
27
port_src/output/zxing/client/result/parsed_result_type.rs
Normal file
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* 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::client::result;
|
||||
|
||||
/**
|
||||
* Represents the type of data encoded by a barcode -- from plain text, to a
|
||||
* URI, to an e-mail address, etc.
|
||||
*
|
||||
* @author Sean Owen
|
||||
*/
|
||||
pub enum ParsedResultType {
|
||||
|
||||
ADDRESSBOOK(), EMAIL_ADDRESS(), PRODUCT(), URI(), TEXT(), GEO(), TEL(), SMS(), CALENDAR(), WIFI(), ISBN(), VIN()
|
||||
}
|
||||
55
port_src/output/zxing/client/result/product_parsed_result.rs
Normal file
55
port_src/output/zxing/client/result/product_parsed_result.rs
Normal file
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* 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::client::result;
|
||||
|
||||
/**
|
||||
* Represents a parsed result that encodes a product by an identifier of some kind.
|
||||
*
|
||||
* @author dswitkin@google.com (Daniel Switkin)
|
||||
*/
|
||||
pub struct ProductParsedResult {
|
||||
super: ParsedResult;
|
||||
|
||||
let product_i_d: String;
|
||||
|
||||
let normalized_product_i_d: String;
|
||||
}
|
||||
|
||||
impl ProductParsedResult {
|
||||
|
||||
fn new( product_i_d: &String) -> ProductParsedResult {
|
||||
this(&product_i_d, &product_i_d);
|
||||
}
|
||||
|
||||
fn new( product_i_d: &String, normalized_product_i_d: &String) -> ProductParsedResult {
|
||||
super(ParsedResultType::PRODUCT);
|
||||
let .productID = product_i_d;
|
||||
let .normalizedProductID = normalized_product_i_d;
|
||||
}
|
||||
|
||||
pub fn get_product_i_d(&self) -> String {
|
||||
return self.product_i_d;
|
||||
}
|
||||
|
||||
pub fn get_normalized_product_i_d(&self) -> String {
|
||||
return self.normalized_product_i_d;
|
||||
}
|
||||
|
||||
pub fn get_display_result(&self) -> String {
|
||||
return self.product_i_d;
|
||||
}
|
||||
}
|
||||
|
||||
50
port_src/output/zxing/client/result/product_result_parser.rs
Normal file
50
port_src/output/zxing/client/result/product_result_parser.rs
Normal file
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* 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::client::result;
|
||||
|
||||
/**
|
||||
* Parses strings of digits that represent a UPC code.
|
||||
*
|
||||
* @author dswitkin@google.com (Daniel Switkin)
|
||||
*/
|
||||
pub struct ProductResultParser {
|
||||
super: ResultParser;
|
||||
}
|
||||
|
||||
impl ProductResultParser {
|
||||
|
||||
// Treat all UPC and EAN variants as UPCs, in the sense that they are all product barcodes.
|
||||
pub fn parse(&self, result: &Result) -> ProductParsedResult {
|
||||
let format: BarcodeFormat = result.get_barcode_format();
|
||||
if !(format == BarcodeFormat::UPC_A || format == BarcodeFormat::UPC_E || format == BarcodeFormat::EAN_8 || format == BarcodeFormat::EAN_13) {
|
||||
return null;
|
||||
}
|
||||
let raw_text: String = get_massaged_text(result);
|
||||
if !is_string_of_digits(&raw_text, &raw_text.length()) {
|
||||
return null;
|
||||
}
|
||||
// Not actually checking the checksum again here
|
||||
let normalized_product_i_d: String;
|
||||
// Expand UPC-E for purposes of searching
|
||||
if format == BarcodeFormat::UPC_E && raw_text.length() == 8 {
|
||||
normalized_product_i_d = UPCEReader::convert_u_p_c_eto_u_p_c_a(&raw_text);
|
||||
} else {
|
||||
normalized_product_i_d = raw_text;
|
||||
}
|
||||
return ProductParsedResult::new(&raw_text, &normalized_product_i_d);
|
||||
}
|
||||
}
|
||||
|
||||
269
port_src/output/zxing/client/result/result_parser.rs
Normal file
269
port_src/output/zxing/client/result/result_parser.rs
Normal file
@@ -0,0 +1,269 @@
|
||||
/*
|
||||
* 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::client::result;
|
||||
|
||||
/**
|
||||
* <p>Abstract class representing the result of decoding a barcode, as more than
|
||||
* a String -- as some type of structured data. This might be a subclass which represents
|
||||
* a URL, or an e-mail address. {@link #parseResult(Result)} will turn a raw
|
||||
* decoded string into the most appropriate type of structured representation.</p>
|
||||
*
|
||||
* <p>Thanks to Jeff Griffin for proposing rewrite of these classes that relies less
|
||||
* on exception-based mechanisms during parsing.</p>
|
||||
*
|
||||
* @author Sean Owen
|
||||
*/
|
||||
|
||||
const PARSERS: vec![Vec<ResultParser>; 20] = vec![BookmarkDoCoMoResultParser::new(), AddressBookDoCoMoResultParser::new(), EmailDoCoMoResultParser::new(), AddressBookAUResultParser::new(), VCardResultParser::new(), BizcardResultParser::new(), VEventResultParser::new(), EmailAddressResultParser::new(), SMTPResultParser::new(), TelResultParser::new(), SMSMMSResultParser::new(), SMSTOMMSTOResultParser::new(), GeoResultParser::new(), WifiResultParser::new(), URLTOResultParser::new(), URIResultParser::new(), ISBNResultParser::new(), ProductResultParser::new(), ExpandedProductResultParser::new(), VINResultParser::new(), ]
|
||||
;
|
||||
|
||||
const DIGITS: Pattern = Pattern::compile("\\d+");
|
||||
|
||||
const AMPERSAND: Pattern = Pattern::compile("&");
|
||||
|
||||
const EQUALS: Pattern = Pattern::compile("=");
|
||||
|
||||
const BYTE_ORDER_MARK: &'static str = "";
|
||||
|
||||
const EMPTY_STR_ARRAY: [Option<String>; 0] = [None; 0];
|
||||
pub struct ResultParser {
|
||||
}
|
||||
|
||||
impl ResultParser {
|
||||
|
||||
/**
|
||||
* Attempts to parse the raw {@link Result}'s contents as a particular type
|
||||
* of information (email, URL, etc.) and return a {@link ParsedResult} encapsulating
|
||||
* the result of parsing.
|
||||
*
|
||||
* @param theResult the raw {@link Result} to parse
|
||||
* @return {@link ParsedResult} encapsulating the parsing result
|
||||
*/
|
||||
pub fn parse(&self, the_result: &Result) -> ParsedResult ;
|
||||
|
||||
pub fn get_massaged_text( result: &Result) -> String {
|
||||
let mut text: String = result.get_text();
|
||||
if text.starts_with(&BYTE_ORDER_MARK) {
|
||||
text = text.substring(1);
|
||||
}
|
||||
return text;
|
||||
}
|
||||
|
||||
pub fn parse_result( the_result: &Result) -> ParsedResult {
|
||||
for let parser: ResultParser in PARSERS {
|
||||
let result: ParsedResult = parser.parse(the_result);
|
||||
if result != null {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return TextParsedResult::new(&the_result.get_text(), null);
|
||||
}
|
||||
|
||||
pub fn maybe_append( value: &String, result: &StringBuilder) {
|
||||
if value != null {
|
||||
result.append('\n');
|
||||
result.append(&value);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn maybe_append( value: &Vec<String>, result: &StringBuilder) {
|
||||
if value != null {
|
||||
for let s: String in value {
|
||||
result.append('\n');
|
||||
result.append(&s);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn maybe_wrap( value: &String) -> Vec<String> {
|
||||
return if value == null { null } else { : vec![String; 1] = vec![value, ]
|
||||
};
|
||||
}
|
||||
|
||||
pub fn unescape_backslash( escaped: &String) -> String {
|
||||
let backslash: i32 = escaped.index_of('\\');
|
||||
if backslash < 0 {
|
||||
return escaped;
|
||||
}
|
||||
let max: i32 = escaped.length();
|
||||
let unescaped: StringBuilder = StringBuilder::new(max - 1);
|
||||
unescaped.append(&escaped.to_char_array(), 0, backslash);
|
||||
let next_is_escaped: bool = false;
|
||||
{
|
||||
let mut i: i32 = backslash;
|
||||
while i < max {
|
||||
{
|
||||
let c: char = escaped.char_at(i);
|
||||
if next_is_escaped || c != '\\' {
|
||||
unescaped.append(c);
|
||||
next_is_escaped = false;
|
||||
} else {
|
||||
next_is_escaped = true;
|
||||
}
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
return unescaped.to_string();
|
||||
}
|
||||
|
||||
pub fn parse_hex_digit( c: char) -> i32 {
|
||||
if c >= '0' && c <= '9' {
|
||||
return c - '0';
|
||||
}
|
||||
if c >= 'a' && c <= 'f' {
|
||||
return 10 + (c - 'a');
|
||||
}
|
||||
if c >= 'A' && c <= 'F' {
|
||||
return 10 + (c - 'A');
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
pub fn is_string_of_digits( value: &CharSequence, length: i32) -> bool {
|
||||
return value != null && length > 0 && length == value.length() && DIGITS::matcher(&value)::matches();
|
||||
}
|
||||
|
||||
pub fn is_substring_of_digits( value: &CharSequence, offset: i32, length: i32) -> bool {
|
||||
if value == null || length <= 0 {
|
||||
return false;
|
||||
}
|
||||
let max: i32 = offset + length;
|
||||
return value.length() >= max && DIGITS::matcher(&value.sub_sequence(offset, max))::matches();
|
||||
}
|
||||
|
||||
fn parse_name_value_pairs( uri: &String) -> Map<String, String> {
|
||||
let param_start: i32 = uri.index_of('?');
|
||||
if param_start < 0 {
|
||||
return null;
|
||||
}
|
||||
let result: Map<String, String> = HashMap<>::new(3);
|
||||
for let key_value: String in AMPERSAND::split(&uri.substring(param_start + 1)) {
|
||||
::append_key_value(&key_value, &result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
fn append_key_value( key_value: &CharSequence, result: &Map<String, String>) {
|
||||
let key_value_tokens: Vec<String> = EQUALS::split(&key_value, 2);
|
||||
if key_value_tokens.len() == 2 {
|
||||
let key: String = key_value_tokens[0];
|
||||
let mut value: String = key_value_tokens[1];
|
||||
let tryResult1 = 0;
|
||||
'try1: loop {
|
||||
{
|
||||
value = ::url_decode(&value);
|
||||
result.put(&key, &value);
|
||||
}
|
||||
break 'try1
|
||||
}
|
||||
match tryResult1 {
|
||||
catch ( iae: &IllegalArgumentException) {
|
||||
} 0 => break
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
fn url_decode( encoded: &String) -> String {
|
||||
let tryResult1 = 0;
|
||||
'try1: loop {
|
||||
{
|
||||
return URLDecoder::decode(&encoded, "UTF-8");
|
||||
}
|
||||
break 'try1
|
||||
}
|
||||
match tryResult1 {
|
||||
catch ( uee: &UnsupportedEncodingException) {
|
||||
throw IllegalStateException::new(&uee);
|
||||
} 0 => break
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fn match_prefixed_field( prefix: &String, raw_text: &String, end_char: char, trim: bool) -> Vec<String> {
|
||||
let mut matches: List<String> = null;
|
||||
let mut i: i32 = 0;
|
||||
let max: i32 = raw_text.length();
|
||||
while i < max {
|
||||
i = raw_text.index_of(&prefix, i);
|
||||
if i < 0 {
|
||||
break;
|
||||
}
|
||||
// Skip past this prefix we found to start
|
||||
i += prefix.length();
|
||||
// Found the start of a match here
|
||||
let start: i32 = i;
|
||||
let mut more: bool = true;
|
||||
while more {
|
||||
i = raw_text.index_of(end_char, i);
|
||||
if i < 0 {
|
||||
// No terminating end character? uh, done. Set i such that loop terminates and break
|
||||
i = raw_text.length();
|
||||
more = false;
|
||||
} else if ::count_preceding_backslashes(&raw_text, i) % 2 != 0 {
|
||||
// semicolon was escaped (odd count of preceding backslashes) so continue
|
||||
i += 1;
|
||||
} else {
|
||||
// found a match
|
||||
if matches == null {
|
||||
// lazy init
|
||||
matches = ArrayList<>::new(3);
|
||||
}
|
||||
let mut element: String = ::unescape_backslash(&raw_text.substring(start, i));
|
||||
if trim {
|
||||
element = element.trim();
|
||||
}
|
||||
if !element.is_empty() {
|
||||
matches.add(&element);
|
||||
}
|
||||
i += 1;
|
||||
more = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
if matches == null || matches.is_empty() {
|
||||
return null;
|
||||
}
|
||||
return matches.to_array(&EMPTY_STR_ARRAY);
|
||||
}
|
||||
|
||||
fn count_preceding_backslashes( s: &CharSequence, pos: i32) -> i32 {
|
||||
let mut count: i32 = 0;
|
||||
{
|
||||
let mut i: i32 = pos - 1;
|
||||
while i >= 0 {
|
||||
{
|
||||
if s.char_at(i) == '\\' {
|
||||
count += 1;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
i -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
fn match_single_prefixed_field( prefix: &String, raw_text: &String, end_char: char, trim: bool) -> String {
|
||||
let matches: Vec<String> = ::match_prefixed_field(&prefix, &raw_text, end_char, trim);
|
||||
return if matches == null { null } else { matches[0] };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* 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::client::result;
|
||||
|
||||
/**
|
||||
* <p>Parses an "sms:" URI result, which specifies a number to SMS.
|
||||
* See <a href="http://tools.ietf.org/html/rfc5724"> RFC 5724</a> on this.</p>
|
||||
*
|
||||
* <p>This class supports "via" syntax for numbers, which is not part of the spec.
|
||||
* For example "+12125551212;via=+12124440101" may appear as a number.
|
||||
* It also supports a "subject" query parameter, which is not mentioned in the spec.
|
||||
* These are included since they were mentioned in earlier IETF drafts and might be
|
||||
* used.</p>
|
||||
*
|
||||
* <p>This actually also parses URIs starting with "mms:" and treats them all the same way,
|
||||
* and effectively converts them to an "sms:" URI for purposes of forwarding to the platform.</p>
|
||||
*
|
||||
* @author Sean Owen
|
||||
*/
|
||||
pub struct SMSMMSResultParser {
|
||||
super: ResultParser;
|
||||
}
|
||||
|
||||
impl SMSMMSResultParser {
|
||||
|
||||
pub fn parse(&self, result: &Result) -> SMSParsedResult {
|
||||
let raw_text: String = get_massaged_text(result);
|
||||
if !(raw_text.starts_with("sms:") || raw_text.starts_with("SMS:") || raw_text.starts_with("mms:") || raw_text.starts_with("MMS:")) {
|
||||
return null;
|
||||
}
|
||||
// Check up front if this is a URI syntax string with query arguments
|
||||
let name_value_pairs: Map<String, String> = parse_name_value_pairs(&raw_text);
|
||||
let mut subject: String = null;
|
||||
let mut body: String = null;
|
||||
let query_syntax: bool = false;
|
||||
if name_value_pairs != null && !name_value_pairs.is_empty() {
|
||||
subject = name_value_pairs.get("subject");
|
||||
body = name_value_pairs.get("body");
|
||||
query_syntax = true;
|
||||
}
|
||||
// Drop sms, query portion
|
||||
let query_start: i32 = raw_text.index_of('?', 4);
|
||||
let sms_u_r_i_without_query: String;
|
||||
// If it's not query syntax, the question mark is part of the subject or message
|
||||
if query_start < 0 || !query_syntax {
|
||||
sms_u_r_i_without_query = raw_text.substring(4);
|
||||
} else {
|
||||
sms_u_r_i_without_query = raw_text.substring(4, query_start);
|
||||
}
|
||||
let last_comma: i32 = -1;
|
||||
let mut comma: i32;
|
||||
let numbers: List<String> = ArrayList<>::new(1);
|
||||
let vias: List<String> = ArrayList<>::new(1);
|
||||
while (comma = sms_u_r_i_without_query.index_of(',', last_comma + 1)) > last_comma {
|
||||
let number_part: String = sms_u_r_i_without_query.substring(last_comma + 1, comma);
|
||||
::add_number_via(&numbers, &vias, &number_part);
|
||||
last_comma = comma;
|
||||
}
|
||||
::add_number_via(&numbers, &vias, &sms_u_r_i_without_query.substring(last_comma + 1));
|
||||
return SMSParsedResult::new(&numbers.to_array(EMPTY_STR_ARRAY), &vias.to_array(EMPTY_STR_ARRAY), &subject, &body);
|
||||
}
|
||||
|
||||
fn add_number_via( numbers: &Collection<String>, vias: &Collection<String>, number_part: &String) {
|
||||
let number_end: i32 = number_part.index_of(';');
|
||||
if number_end < 0 {
|
||||
numbers.add(&number_part);
|
||||
vias.add(null);
|
||||
} else {
|
||||
numbers.add(&number_part.substring(0, number_end));
|
||||
let maybe_via: String = number_part.substring(number_end + 1);
|
||||
let mut via: String;
|
||||
if maybe_via.starts_with("via=") {
|
||||
via = maybe_via.substring(4);
|
||||
} else {
|
||||
via = null;
|
||||
}
|
||||
vias.add(&via);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
122
port_src/output/zxing/client/result/s_m_s_parsed_result.rs
Normal file
122
port_src/output/zxing/client/result/s_m_s_parsed_result.rs
Normal file
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
* 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::client::result;
|
||||
|
||||
/**
|
||||
* Represents a parsed result that encodes an SMS message, including recipients, subject
|
||||
* and body text.
|
||||
*
|
||||
* @author Sean Owen
|
||||
*/
|
||||
pub struct SMSParsedResult {
|
||||
super: ParsedResult;
|
||||
|
||||
let mut numbers: Vec<String>;
|
||||
|
||||
let mut vias: Vec<String>;
|
||||
|
||||
let subject: String;
|
||||
|
||||
let body: String;
|
||||
}
|
||||
|
||||
impl SMSParsedResult {
|
||||
|
||||
pub fn new( number: &String, via: &String, subject: &String, body: &String) -> SMSParsedResult {
|
||||
super(ParsedResultType::SMS);
|
||||
let .numbers = : vec![String; 1] = vec![number, ]
|
||||
;
|
||||
let .vias = : vec![String; 1] = vec![via, ]
|
||||
;
|
||||
let .subject = subject;
|
||||
let .body = body;
|
||||
}
|
||||
|
||||
pub fn new( numbers: &Vec<String>, vias: &Vec<String>, subject: &String, body: &String) -> SMSParsedResult {
|
||||
super(ParsedResultType::SMS);
|
||||
let .numbers = numbers;
|
||||
let .vias = vias;
|
||||
let .subject = subject;
|
||||
let .body = body;
|
||||
}
|
||||
|
||||
pub fn get_s_m_s_u_r_i(&self) -> String {
|
||||
let result: StringBuilder = StringBuilder::new();
|
||||
result.append("sms:");
|
||||
let mut first: bool = true;
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < self.numbers.len() {
|
||||
{
|
||||
if first {
|
||||
first = false;
|
||||
} else {
|
||||
result.append(',');
|
||||
}
|
||||
result.append(self.numbers[i]);
|
||||
if self.vias != null && self.vias[i] != null {
|
||||
result.append(";via=");
|
||||
result.append(self.vias[i]);
|
||||
}
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
let has_body: bool = self.body != null;
|
||||
let has_subject: bool = self.subject != null;
|
||||
if has_body || has_subject {
|
||||
result.append('?');
|
||||
if has_body {
|
||||
result.append("body=");
|
||||
result.append(&self.body);
|
||||
}
|
||||
if has_subject {
|
||||
if has_body {
|
||||
result.append('&');
|
||||
}
|
||||
result.append("subject=");
|
||||
result.append(&self.subject);
|
||||
}
|
||||
}
|
||||
return result.to_string();
|
||||
}
|
||||
|
||||
pub fn get_numbers(&self) -> Vec<String> {
|
||||
return self.numbers;
|
||||
}
|
||||
|
||||
pub fn get_vias(&self) -> Vec<String> {
|
||||
return self.vias;
|
||||
}
|
||||
|
||||
pub fn get_subject(&self) -> String {
|
||||
return self.subject;
|
||||
}
|
||||
|
||||
pub fn get_body(&self) -> String {
|
||||
return self.body;
|
||||
}
|
||||
|
||||
pub fn get_display_result(&self) -> String {
|
||||
let result: StringBuilder = StringBuilder::new(100);
|
||||
maybe_append(&self.numbers, &result);
|
||||
maybe_append(&self.subject, &result);
|
||||
maybe_append(&self.body, &result);
|
||||
return result.to_string();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* 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::client::result;
|
||||
|
||||
/**
|
||||
* <p>Parses an "smsto:" URI result, whose format is not standardized but appears to be like:
|
||||
* {@code smsto:number(:body)}.</p>
|
||||
*
|
||||
* <p>This actually also parses URIs starting with "smsto:", "mmsto:", "SMSTO:", and
|
||||
* "MMSTO:", and treats them all the same way, and effectively converts them to an "sms:" URI
|
||||
* for purposes of forwarding to the platform.</p>
|
||||
*
|
||||
* @author Sean Owen
|
||||
*/
|
||||
pub struct SMSTOMMSTOResultParser {
|
||||
super: ResultParser;
|
||||
}
|
||||
|
||||
impl SMSTOMMSTOResultParser {
|
||||
|
||||
pub fn parse(&self, result: &Result) -> SMSParsedResult {
|
||||
let raw_text: String = get_massaged_text(result);
|
||||
if !(raw_text.starts_with("smsto:") || raw_text.starts_with("SMSTO:") || raw_text.starts_with("mmsto:") || raw_text.starts_with("MMSTO:")) {
|
||||
return null;
|
||||
}
|
||||
// Thanks to dominik.wild for suggesting this enhancement to support
|
||||
// smsto:number:body URIs
|
||||
let mut number: String = raw_text.substring(6);
|
||||
let mut body: String = null;
|
||||
let body_start: i32 = number.index_of(':');
|
||||
if body_start >= 0 {
|
||||
body = number.substring(body_start + 1);
|
||||
number = number.substring(0, body_start);
|
||||
}
|
||||
return SMSParsedResult::new(&number, null, null, &body);
|
||||
}
|
||||
}
|
||||
|
||||
52
port_src/output/zxing/client/result/s_m_t_p_result_parser.rs
Normal file
52
port_src/output/zxing/client/result/s_m_t_p_result_parser.rs
Normal file
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* 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::client::result;
|
||||
|
||||
/**
|
||||
* <p>Parses an "smtp:" URI result, whose format is not standardized but appears to be like:
|
||||
* {@code smtp[:subject[:body]]}.</p>
|
||||
*
|
||||
* @author Sean Owen
|
||||
*/
|
||||
pub struct SMTPResultParser {
|
||||
super: ResultParser;
|
||||
}
|
||||
|
||||
impl SMTPResultParser {
|
||||
|
||||
pub fn parse(&self, result: &Result) -> EmailAddressParsedResult {
|
||||
let raw_text: String = get_massaged_text(result);
|
||||
if !(raw_text.starts_with("smtp:") || raw_text.starts_with("SMTP:")) {
|
||||
return null;
|
||||
}
|
||||
let email_address: String = raw_text.substring(5);
|
||||
let mut subject: String = null;
|
||||
let mut body: String = null;
|
||||
let mut colon: i32 = email_address.index_of(':');
|
||||
if colon >= 0 {
|
||||
subject = email_address.substring(colon + 1);
|
||||
email_address = email_address.substring(0, colon);
|
||||
colon = subject.index_of(':');
|
||||
if colon >= 0 {
|
||||
body = subject.substring(colon + 1);
|
||||
subject = subject.substring(0, colon);
|
||||
}
|
||||
}
|
||||
return EmailAddressParsedResult::new( : vec![String; 1] = vec![email_address, ]
|
||||
, null, null, &subject, &body);
|
||||
}
|
||||
}
|
||||
|
||||
61
port_src/output/zxing/client/result/tel_parsed_result.rs
Normal file
61
port_src/output/zxing/client/result/tel_parsed_result.rs
Normal file
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* 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::client::result;
|
||||
|
||||
/**
|
||||
* Represents a parsed result that encodes a telephone number.
|
||||
*
|
||||
* @author Sean Owen
|
||||
*/
|
||||
pub struct TelParsedResult {
|
||||
super: ParsedResult;
|
||||
|
||||
let number: String;
|
||||
|
||||
let tel_u_r_i: String;
|
||||
|
||||
let title: String;
|
||||
}
|
||||
|
||||
impl TelParsedResult {
|
||||
|
||||
pub fn new( number: &String, tel_u_r_i: &String, title: &String) -> TelParsedResult {
|
||||
super(ParsedResultType::TEL);
|
||||
let .number = number;
|
||||
let .telURI = tel_u_r_i;
|
||||
let .title = title;
|
||||
}
|
||||
|
||||
pub fn get_number(&self) -> String {
|
||||
return self.number;
|
||||
}
|
||||
|
||||
pub fn get_tel_u_r_i(&self) -> String {
|
||||
return self.tel_u_r_i;
|
||||
}
|
||||
|
||||
pub fn get_title(&self) -> String {
|
||||
return self.title;
|
||||
}
|
||||
|
||||
pub fn get_display_result(&self) -> String {
|
||||
let result: StringBuilder = StringBuilder::new(20);
|
||||
maybe_append(&self.number, &result);
|
||||
maybe_append(&self.title, &result);
|
||||
return result.to_string();
|
||||
}
|
||||
}
|
||||
|
||||
42
port_src/output/zxing/client/result/tel_result_parser.rs
Normal file
42
port_src/output/zxing/client/result/tel_result_parser.rs
Normal file
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* 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::client::result;
|
||||
|
||||
/**
|
||||
* Parses a "tel:" URI result, which specifies a phone number.
|
||||
*
|
||||
* @author Sean Owen
|
||||
*/
|
||||
pub struct TelResultParser {
|
||||
super: ResultParser;
|
||||
}
|
||||
|
||||
impl TelResultParser {
|
||||
|
||||
pub fn parse(&self, result: &Result) -> TelParsedResult {
|
||||
let raw_text: String = get_massaged_text(result);
|
||||
if !raw_text.starts_with("tel:") && !raw_text.starts_with("TEL:") {
|
||||
return null;
|
||||
}
|
||||
// Normalize "TEL:" to "tel:"
|
||||
let tel_u_r_i: String = if raw_text.starts_with("TEL:") { format!("tel:{}", raw_text.substring(4)) } else { raw_text };
|
||||
// Drop tel, query portion
|
||||
let query_start: i32 = raw_text.index_of('?', 4);
|
||||
let number: String = if query_start < 0 { raw_text.substring(4) } else { raw_text.substring(4, query_start) };
|
||||
return TelParsedResult::new(&number, &tel_u_r_i, null);
|
||||
}
|
||||
}
|
||||
|
||||
52
port_src/output/zxing/client/result/text_parsed_result.rs
Normal file
52
port_src/output/zxing/client/result/text_parsed_result.rs
Normal file
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* 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::client::result;
|
||||
|
||||
/**
|
||||
* A simple result type encapsulating a string that has no further
|
||||
* interpretation.
|
||||
*
|
||||
* @author Sean Owen
|
||||
*/
|
||||
pub struct TextParsedResult {
|
||||
super: ParsedResult;
|
||||
|
||||
let text: String;
|
||||
|
||||
let language: String;
|
||||
}
|
||||
|
||||
impl TextParsedResult {
|
||||
|
||||
pub fn new( text: &String, language: &String) -> TextParsedResult {
|
||||
super(ParsedResultType::TEXT);
|
||||
let .text = text;
|
||||
let .language = language;
|
||||
}
|
||||
|
||||
pub fn get_text(&self) -> String {
|
||||
return self.text;
|
||||
}
|
||||
|
||||
pub fn get_language(&self) -> String {
|
||||
return self.language;
|
||||
}
|
||||
|
||||
pub fn get_display_result(&self) -> String {
|
||||
return self.text;
|
||||
}
|
||||
}
|
||||
|
||||
87
port_src/output/zxing/client/result/u_r_i_parsed_result.rs
Normal file
87
port_src/output/zxing/client/result/u_r_i_parsed_result.rs
Normal file
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* 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::client::result;
|
||||
|
||||
/**
|
||||
* A simple result type encapsulating a URI that has no further interpretation.
|
||||
*
|
||||
* @author Sean Owen
|
||||
*/
|
||||
pub struct URIParsedResult {
|
||||
super: ParsedResult;
|
||||
|
||||
let uri: String;
|
||||
|
||||
let title: String;
|
||||
}
|
||||
|
||||
impl URIParsedResult {
|
||||
|
||||
pub fn new( uri: &String, title: &String) -> URIParsedResult {
|
||||
super(ParsedResultType::URI);
|
||||
let .uri = ::massage_u_r_i(&uri);
|
||||
let .title = title;
|
||||
}
|
||||
|
||||
pub fn get_u_r_i(&self) -> String {
|
||||
return self.uri;
|
||||
}
|
||||
|
||||
pub fn get_title(&self) -> String {
|
||||
return self.title;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if the URI contains suspicious patterns that may suggest it intends to
|
||||
* mislead the user about its true nature
|
||||
* @deprecated see {@link URIResultParser#isPossiblyMaliciousURI(String)}
|
||||
*/
|
||||
pub fn is_possibly_malicious_u_r_i(&self) -> bool {
|
||||
return URIResultParser::is_possibly_malicious_u_r_i(&self.uri);
|
||||
}
|
||||
|
||||
pub fn get_display_result(&self) -> String {
|
||||
let result: StringBuilder = StringBuilder::new(30);
|
||||
maybe_append(&self.title, &result);
|
||||
maybe_append(&self.uri, &result);
|
||||
return result.to_string();
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms a string that represents a URI into something more proper, by adding or canonicalizing
|
||||
* the protocol.
|
||||
*/
|
||||
fn massage_u_r_i( uri: &String) -> String {
|
||||
uri = uri.trim();
|
||||
let protocol_end: i32 = uri.index_of(':');
|
||||
if protocol_end < 0 || ::is_colon_followed_by_port_number(&uri, protocol_end) {
|
||||
// No protocol, or found a colon, but it looks like it is after the host, so the protocol is still missing,
|
||||
// so assume http
|
||||
uri = format!("http://{}", uri);
|
||||
}
|
||||
return uri;
|
||||
}
|
||||
|
||||
fn is_colon_followed_by_port_number( uri: &String, protocol_end: i32) -> bool {
|
||||
let start: i32 = protocol_end + 1;
|
||||
let next_slash: i32 = uri.index_of('/', start);
|
||||
if next_slash < 0 {
|
||||
next_slash = uri.length();
|
||||
}
|
||||
return ResultParser::is_substring_of_digits(&uri, start, next_slash - start);
|
||||
}
|
||||
}
|
||||
|
||||
77
port_src/output/zxing/client/result/u_r_i_result_parser.rs
Normal file
77
port_src/output/zxing/client/result/u_r_i_result_parser.rs
Normal file
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* 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::client::result;
|
||||
|
||||
/**
|
||||
* Tries to parse results that are a URI of some kind.
|
||||
*
|
||||
* @author Sean Owen
|
||||
*/
|
||||
|
||||
const ALLOWED_URI_CHARS_PATTERN: Pattern = Pattern::compile("[-._~:/?#\\[\\]@!$&'()*+,;=%A-Za-z0-9]+");
|
||||
|
||||
const USER_IN_HOST: Pattern = Pattern::compile(":/*([^/@]+)@[^/]+");
|
||||
|
||||
// See http://www.ietf.org/rfc/rfc2396.txt
|
||||
const URL_WITH_PROTOCOL_PATTERN: Pattern = Pattern::compile("[a-zA-Z][a-zA-Z0-9+-.]+:");
|
||||
|
||||
const URL_WITHOUT_PROTOCOL_PATTERN: Pattern = Pattern::compile(format!("([a-zA-Z0-9\\-]+\\.){1,6}[a-zA-Z]{2,}(:\\d{1,5})?(/|\\?|$)"));
|
||||
pub struct URIResultParser {
|
||||
super: ResultParser;
|
||||
}
|
||||
|
||||
impl URIResultParser {
|
||||
|
||||
pub fn parse(&self, result: &Result) -> URIParsedResult {
|
||||
let raw_text: String = get_massaged_text(result);
|
||||
// Assume anything starting this way really means to be a URI
|
||||
if raw_text.starts_with("URL:") || raw_text.starts_with("URI:") {
|
||||
return URIParsedResult::new(&raw_text.substring(4).trim(), null);
|
||||
}
|
||||
raw_text = raw_text.trim();
|
||||
if !::is_basically_valid_u_r_i(&raw_text) || ::is_possibly_malicious_u_r_i(&raw_text) {
|
||||
return null;
|
||||
}
|
||||
return URIParsedResult::new(&raw_text, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if the URI contains suspicious patterns that may suggest it intends to
|
||||
* mislead the user about its true nature. At the moment this looks for the presence
|
||||
* of user/password syntax in the host/authority portion of a URI which may be used
|
||||
* in attempts to make the URI's host appear to be other than it is. Example:
|
||||
* http://yourbank.com@phisher.com This URI connects to phisher.com but may appear
|
||||
* to connect to yourbank.com at first glance.
|
||||
*/
|
||||
fn is_possibly_malicious_u_r_i( uri: &String) -> bool {
|
||||
return !ALLOWED_URI_CHARS_PATTERN::matcher(&uri)::matches() || USER_IN_HOST::matcher(&uri)::find();
|
||||
}
|
||||
|
||||
fn is_basically_valid_u_r_i( uri: &String) -> bool {
|
||||
if uri.contains(" ") {
|
||||
// Quick hack check for a common case
|
||||
return false;
|
||||
}
|
||||
let mut m: Matcher = URL_WITH_PROTOCOL_PATTERN::matcher(&uri);
|
||||
if m.find() && m.start() == 0 {
|
||||
// match at start only
|
||||
return true;
|
||||
}
|
||||
m = URL_WITHOUT_PROTOCOL_PATTERN::matcher(&uri);
|
||||
return m.find() && m.start() == 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* 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::client::result;
|
||||
|
||||
/**
|
||||
* Parses the "URLTO" result format, which is of the form "URLTO:[title]:[url]".
|
||||
* This seems to be used sometimes, but I am not able to find documentation
|
||||
* on its origin or official format?
|
||||
*
|
||||
* @author Sean Owen
|
||||
*/
|
||||
pub struct URLTOResultParser {
|
||||
super: ResultParser;
|
||||
}
|
||||
|
||||
impl URLTOResultParser {
|
||||
|
||||
pub fn parse(&self, result: &Result) -> URIParsedResult {
|
||||
let raw_text: String = get_massaged_text(result);
|
||||
if !raw_text.starts_with("urlto:") && !raw_text.starts_with("URLTO:") {
|
||||
return null;
|
||||
}
|
||||
let title_end: i32 = raw_text.index_of(':', 6);
|
||||
if title_end < 0 {
|
||||
return null;
|
||||
}
|
||||
let title: String = if title_end <= 6 { null } else { raw_text.substring(6, title_end) };
|
||||
let uri: String = raw_text.substring(title_end + 1);
|
||||
return URIParsedResult::new(&uri, &title);
|
||||
}
|
||||
}
|
||||
|
||||
387
port_src/output/zxing/client/result/v_card_result_parser.rs
Normal file
387
port_src/output/zxing/client/result/v_card_result_parser.rs
Normal file
@@ -0,0 +1,387 @@
|
||||
/*
|
||||
* 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::client::result;
|
||||
|
||||
/**
|
||||
* Parses contact information formatted according to the VCard (2.1) format. This is not a complete
|
||||
* implementation but should parse information as commonly encoded in 2D barcodes.
|
||||
*
|
||||
* @author Sean Owen
|
||||
*/
|
||||
|
||||
const BEGIN_VCARD: Pattern = Pattern::compile("BEGIN:VCARD", Pattern::CASE_INSENSITIVE);
|
||||
|
||||
const VCARD_LIKE_DATE: Pattern = Pattern::compile("\\d{4}-?\\d{2}-?\\d{2}");
|
||||
|
||||
const CR_LF_SPACE_TAB: Pattern = Pattern::compile("\r\n[ \t]");
|
||||
|
||||
const NEWLINE_ESCAPE: Pattern = Pattern::compile("\\\\[nN]");
|
||||
|
||||
const VCARD_ESCAPES: Pattern = Pattern::compile("\\\\([,;\\\\])");
|
||||
|
||||
const EQUALS: Pattern = Pattern::compile("=");
|
||||
|
||||
const SEMICOLON: Pattern = Pattern::compile(";");
|
||||
|
||||
const UNESCAPED_SEMICOLONS: Pattern = Pattern::compile("(?<!\\\\);+");
|
||||
|
||||
const COMMA: Pattern = Pattern::compile(",");
|
||||
|
||||
const SEMICOLON_OR_COMMA: Pattern = Pattern::compile("[;,]");
|
||||
pub struct VCardResultParser {
|
||||
super: ResultParser;
|
||||
}
|
||||
|
||||
impl VCardResultParser {
|
||||
|
||||
pub fn parse(&self, result: &Result) -> AddressBookParsedResult {
|
||||
// Although we should insist on the raw text ending with "END:VCARD", there's no reason
|
||||
// to throw out everything else we parsed just because this was omitted. In fact, Eclair
|
||||
// is doing just that, and we can't parse its contacts without this leniency.
|
||||
let raw_text: String = get_massaged_text(result);
|
||||
let m: Matcher = BEGIN_VCARD::matcher(&raw_text);
|
||||
if !m.find() || m.start() != 0 {
|
||||
return null;
|
||||
}
|
||||
let mut names: List<List<String>> = ::match_v_card_prefixed_field("FN", &raw_text, true, false);
|
||||
if names == null {
|
||||
// If no display names found, look for regular name fields and format them
|
||||
names = ::match_v_card_prefixed_field("N", &raw_text, true, false);
|
||||
::format_names(&names);
|
||||
}
|
||||
let nickname_string: List<String> = ::match_single_v_card_prefixed_field("NICKNAME", &raw_text, true, false);
|
||||
let nicknames: Vec<String> = if nickname_string == null { null } else { COMMA::split(&nickname_string.get(0)) };
|
||||
let phone_numbers: List<List<String>> = ::match_v_card_prefixed_field("TEL", &raw_text, true, false);
|
||||
let emails: List<List<String>> = ::match_v_card_prefixed_field("EMAIL", &raw_text, true, false);
|
||||
let note: List<String> = ::match_single_v_card_prefixed_field("NOTE", &raw_text, false, false);
|
||||
let addresses: List<List<String>> = ::match_v_card_prefixed_field("ADR", &raw_text, true, true);
|
||||
let org: List<String> = ::match_single_v_card_prefixed_field("ORG", &raw_text, true, true);
|
||||
let mut birthday: List<String> = ::match_single_v_card_prefixed_field("BDAY", &raw_text, true, false);
|
||||
if birthday != null && !::is_like_v_card_date(&birthday.get(0)) {
|
||||
birthday = null;
|
||||
}
|
||||
let title: List<String> = ::match_single_v_card_prefixed_field("TITLE", &raw_text, true, false);
|
||||
let urls: List<List<String>> = ::match_v_card_prefixed_field("URL", &raw_text, true, false);
|
||||
let instant_messenger: List<String> = ::match_single_v_card_prefixed_field("IMPP", &raw_text, true, false);
|
||||
let geo_string: List<String> = ::match_single_v_card_prefixed_field("GEO", &raw_text, true, false);
|
||||
let mut geo: Vec<String> = if geo_string == null { null } else { SEMICOLON_OR_COMMA::split(&geo_string.get(0)) };
|
||||
if geo != null && geo.len() != 2 {
|
||||
geo = null;
|
||||
}
|
||||
return AddressBookParsedResult::new(&::to_primary_values(&names), &nicknames, null, &::to_primary_values(&phone_numbers), &::to_types(&phone_numbers), &::to_primary_values(&emails), &::to_types(&emails), &::to_primary_value(&instant_messenger), &::to_primary_value(¬e), &::to_primary_values(&addresses), &::to_types(&addresses), &::to_primary_value(&org), &::to_primary_value(&birthday), &::to_primary_value(&title), &::to_primary_values(&urls), &geo);
|
||||
}
|
||||
|
||||
fn match_v_card_prefixed_field( prefix: &CharSequence, raw_text: &String, trim: bool, parse_field_divider: bool) -> List<List<String>> {
|
||||
let mut matches: List<List<String>> = null;
|
||||
let mut i: i32 = 0;
|
||||
let max: i32 = raw_text.length();
|
||||
while i < max {
|
||||
// At start or after newline, match prefix, followed by optional metadata
|
||||
// (led by ;) ultimately ending in colon
|
||||
let matcher: Matcher = Pattern::compile(format!("(?:^|\n){}(?:;([^:]*))?:", prefix), Pattern::CASE_INSENSITIVE)::matcher(&raw_text);
|
||||
if i > 0 {
|
||||
// Find from i-1 not i since looking at the preceding character
|
||||
i -= 1;
|
||||
}
|
||||
if !matcher.find(i) {
|
||||
break;
|
||||
}
|
||||
// group 0 = whole pattern; end(0) is past final colon
|
||||
i = matcher.end(0);
|
||||
// group 1 = metadata substring
|
||||
let metadata_string: String = matcher.group(1);
|
||||
let mut metadata: List<String> = null;
|
||||
let quoted_printable: bool = false;
|
||||
let quoted_printable_charset: String = null;
|
||||
let value_type: String = null;
|
||||
if metadata_string != null {
|
||||
for let metadatum: String in SEMICOLON::split(&metadata_string) {
|
||||
if metadata == null {
|
||||
metadata = ArrayList<>::new(1);
|
||||
}
|
||||
metadata.add(&metadatum);
|
||||
let metadatum_tokens: Vec<String> = EQUALS::split(&metadatum, 2);
|
||||
if metadatum_tokens.len() > 1 {
|
||||
let key: String = metadatum_tokens[0];
|
||||
let value: String = metadatum_tokens[1];
|
||||
if "ENCODING".equals_ignore_case(&key) && "QUOTED-PRINTABLE".equals_ignore_case(&value) {
|
||||
quoted_printable = true;
|
||||
} else if "CHARSET".equals_ignore_case(&key) {
|
||||
quoted_printable_charset = value;
|
||||
} else if "VALUE".equals_ignore_case(&key) {
|
||||
value_type = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Found the start of a match here
|
||||
let match_start: i32 = i;
|
||||
while (i = raw_text.index_of('\n', i)) >= 0 {
|
||||
// Really, end in \r\n
|
||||
if // But if followed by tab or space,
|
||||
i < raw_text.length() - 1 && (// this is only a continuation
|
||||
raw_text.char_at(i + 1) == ' ' || raw_text.char_at(i + 1) == '\t') {
|
||||
// Skip \n and continutation whitespace
|
||||
i += 2;
|
||||
} else if // If preceded by = in quoted printable
|
||||
quoted_printable && (// this is a continuation
|
||||
(i >= 1 && raw_text.char_at(i - 1) == '=') || (i >= 2 && raw_text.char_at(i - 2) == '=')) {
|
||||
// Skip \n
|
||||
i += 1;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if i < 0 {
|
||||
// No terminating end character? uh, done. Set i such that loop terminates and break
|
||||
i = max;
|
||||
} else if i > match_start {
|
||||
// found a match
|
||||
if matches == null {
|
||||
// lazy init
|
||||
matches = ArrayList<>::new(1);
|
||||
}
|
||||
if i >= 1 && raw_text.char_at(i - 1) == '\r' {
|
||||
// Back up over \r, which really should be there
|
||||
i -= 1;
|
||||
}
|
||||
let mut element: String = raw_text.substring(match_start, i);
|
||||
if trim {
|
||||
element = element.trim();
|
||||
}
|
||||
if quoted_printable {
|
||||
element = ::decode_quoted_printable(&element, "ed_printable_charset);
|
||||
if parse_field_divider {
|
||||
element = UNESCAPED_SEMICOLONS::matcher(&element)::replace_all("\n")::trim();
|
||||
}
|
||||
} else {
|
||||
if parse_field_divider {
|
||||
element = UNESCAPED_SEMICOLONS::matcher(&element)::replace_all("\n")::trim();
|
||||
}
|
||||
element = CR_LF_SPACE_TAB::matcher(&element)::replace_all("");
|
||||
element = NEWLINE_ESCAPE::matcher(&element)::replace_all("\n");
|
||||
element = VCARD_ESCAPES::matcher(&element)::replace_all("$1");
|
||||
}
|
||||
// Only handle VALUE=uri specially
|
||||
if "uri".equals(&value_type) {
|
||||
// as value, to support tel: and mailto:
|
||||
let tryResult1 = 0;
|
||||
'try1: loop {
|
||||
{
|
||||
element = URI::create(&element)::get_scheme_specific_part();
|
||||
}
|
||||
break 'try1
|
||||
}
|
||||
match tryResult1 {
|
||||
catch ( iae: &IllegalArgumentException) {
|
||||
} 0 => break
|
||||
}
|
||||
|
||||
}
|
||||
if metadata == null {
|
||||
let match: List<String> = ArrayList<>::new(1);
|
||||
match.add(&element);
|
||||
matches.add(&match);
|
||||
} else {
|
||||
metadata.add(0, &element);
|
||||
matches.add(&metadata);
|
||||
}
|
||||
i += 1;
|
||||
} else {
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
return matches;
|
||||
}
|
||||
|
||||
fn decode_quoted_printable( value: &CharSequence, charset: &String) -> String {
|
||||
let length: i32 = value.length();
|
||||
let result: StringBuilder = StringBuilder::new(length);
|
||||
let fragment_buffer: ByteArrayOutputStream = ByteArrayOutputStream::new();
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < length {
|
||||
{
|
||||
let c: char = value.char_at(i);
|
||||
match c {
|
||||
'\r' =>
|
||||
{
|
||||
}
|
||||
'\n' =>
|
||||
{
|
||||
break;
|
||||
}
|
||||
'=' =>
|
||||
{
|
||||
if i < length - 2 {
|
||||
let next_char: char = value.char_at(i + 1);
|
||||
if next_char != '\r' && next_char != '\n' {
|
||||
let next_next_char: char = value.char_at(i + 2);
|
||||
let first_digit: i32 = parse_hex_digit(next_char);
|
||||
let second_digit: i32 = parse_hex_digit(next_next_char);
|
||||
if first_digit >= 0 && second_digit >= 0 {
|
||||
fragment_buffer.write((first_digit << 4) + second_digit);
|
||||
}
|
||||
// else ignore it, assume it was incorrectly encoded
|
||||
i += 2;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
_ =>
|
||||
{
|
||||
::maybe_append_fragment(&fragment_buffer, &charset, &result);
|
||||
result.append(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
::maybe_append_fragment(&fragment_buffer, &charset, &result);
|
||||
return result.to_string();
|
||||
}
|
||||
|
||||
fn maybe_append_fragment( fragment_buffer: &ByteArrayOutputStream, charset: &String, result: &StringBuilder) {
|
||||
if fragment_buffer.size() > 0 {
|
||||
let fragment_bytes: Vec<i8> = fragment_buffer.to_byte_array();
|
||||
let mut fragment: String;
|
||||
if charset == null {
|
||||
fragment = String::new(&fragment_bytes, StandardCharsets::UTF_8);
|
||||
} else {
|
||||
let tryResult1 = 0;
|
||||
'try1: loop {
|
||||
{
|
||||
fragment = String::new(&fragment_bytes, &charset);
|
||||
}
|
||||
break 'try1
|
||||
}
|
||||
match tryResult1 {
|
||||
catch ( e: &UnsupportedEncodingException) {
|
||||
fragment = String::new(&fragment_bytes, StandardCharsets::UTF_8);
|
||||
} 0 => break
|
||||
}
|
||||
|
||||
}
|
||||
fragment_buffer.reset();
|
||||
result.append(&fragment);
|
||||
}
|
||||
}
|
||||
|
||||
fn match_single_v_card_prefixed_field( prefix: &CharSequence, raw_text: &String, trim: bool, parse_field_divider: bool) -> List<String> {
|
||||
let values: List<List<String>> = ::match_v_card_prefixed_field(&prefix, &raw_text, trim, parse_field_divider);
|
||||
return if values == null || values.is_empty() { null } else { values.get(0) };
|
||||
}
|
||||
|
||||
fn to_primary_value( list: &List<String>) -> String {
|
||||
return if list == null || list.is_empty() { null } else { list.get(0) };
|
||||
}
|
||||
|
||||
fn to_primary_values( lists: &Collection<List<String>>) -> Vec<String> {
|
||||
if lists == null || lists.is_empty() {
|
||||
return null;
|
||||
}
|
||||
let result: List<String> = ArrayList<>::new(&lists.size());
|
||||
for let list: List<String> in lists {
|
||||
let value: String = list.get(0);
|
||||
if value != null && !value.is_empty() {
|
||||
result.add(&value);
|
||||
}
|
||||
}
|
||||
return result.to_array(EMPTY_STR_ARRAY);
|
||||
}
|
||||
|
||||
fn to_types( lists: &Collection<List<String>>) -> Vec<String> {
|
||||
if lists == null || lists.is_empty() {
|
||||
return null;
|
||||
}
|
||||
let result: List<String> = ArrayList<>::new(&lists.size());
|
||||
for let list: List<String> in lists {
|
||||
let value: String = list.get(0);
|
||||
if value != null && !value.is_empty() {
|
||||
let mut type: String = null;
|
||||
{
|
||||
let mut i: i32 = 1;
|
||||
while i < list.size() {
|
||||
{
|
||||
let metadatum: String = list.get(i);
|
||||
let equals: i32 = metadatum.index_of('=');
|
||||
if equals < 0 {
|
||||
// take the whole thing as a usable label
|
||||
type = metadatum;
|
||||
break;
|
||||
}
|
||||
if "TYPE".equals_ignore_case(&metadatum.substring(0, equals)) {
|
||||
type = metadatum.substring(equals + 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
result.add(&type);
|
||||
}
|
||||
}
|
||||
return result.to_array(EMPTY_STR_ARRAY);
|
||||
}
|
||||
|
||||
fn is_like_v_card_date( value: &CharSequence) -> bool {
|
||||
return value == null || VCARD_LIKE_DATE::matcher(&value)::matches();
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats name fields of the form "Public;John;Q.;Reverend;III" into a form like
|
||||
* "Reverend John Q. Public III".
|
||||
*
|
||||
* @param names name values to format, in place
|
||||
*/
|
||||
fn format_names( names: &Iterable<List<String>>) {
|
||||
if names != null {
|
||||
for let list: List<String> in names {
|
||||
let name: String = list.get(0);
|
||||
let mut components: [Option<String>; 5] = [None; 5];
|
||||
let mut start: i32 = 0;
|
||||
let mut end: i32;
|
||||
let component_index: i32 = 0;
|
||||
while component_index < components.len() - 1 && (end = name.index_of(';', start)) >= 0 {
|
||||
components[component_index] = name.substring(start, end);
|
||||
component_index += 1;
|
||||
start = end + 1;
|
||||
}
|
||||
components[component_index] = name.substring(start);
|
||||
let new_name: StringBuilder = StringBuilder::new(100);
|
||||
::maybe_append_component(&components, 3, &new_name);
|
||||
::maybe_append_component(&components, 1, &new_name);
|
||||
::maybe_append_component(&components, 2, &new_name);
|
||||
::maybe_append_component(&components, 0, &new_name);
|
||||
::maybe_append_component(&components, 4, &new_name);
|
||||
list.set(0, &new_name.to_string().trim());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn maybe_append_component( components: &Vec<String>, i: i32, new_name: &StringBuilder) {
|
||||
if components[i] != null && !components[i].is_empty() {
|
||||
if new_name.length() > 0 {
|
||||
new_name.append(' ');
|
||||
}
|
||||
new_name.append(components[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
132
port_src/output/zxing/client/result/v_event_result_parser.rs
Normal file
132
port_src/output/zxing/client/result/v_event_result_parser.rs
Normal file
@@ -0,0 +1,132 @@
|
||||
/*
|
||||
* 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::client::result;
|
||||
|
||||
/**
|
||||
* Partially implements the iCalendar format's "VEVENT" format for specifying a
|
||||
* calendar event. See RFC 2445. This supports SUMMARY, LOCATION, GEO, DTSTART and DTEND fields.
|
||||
*
|
||||
* @author Sean Owen
|
||||
*/
|
||||
pub struct VEventResultParser {
|
||||
super: ResultParser;
|
||||
}
|
||||
|
||||
impl VEventResultParser {
|
||||
|
||||
pub fn parse(&self, result: &Result) -> CalendarParsedResult {
|
||||
let raw_text: String = get_massaged_text(result);
|
||||
let v_event_start: i32 = raw_text.index_of("BEGIN:VEVENT");
|
||||
if v_event_start < 0 {
|
||||
return null;
|
||||
}
|
||||
let summary: String = ::match_single_v_card_prefixed_field("SUMMARY", &raw_text);
|
||||
let start: String = ::match_single_v_card_prefixed_field("DTSTART", &raw_text);
|
||||
if start == null {
|
||||
return null;
|
||||
}
|
||||
let end: String = ::match_single_v_card_prefixed_field("DTEND", &raw_text);
|
||||
let duration: String = ::match_single_v_card_prefixed_field("DURATION", &raw_text);
|
||||
let location: String = ::match_single_v_card_prefixed_field("LOCATION", &raw_text);
|
||||
let organizer: String = ::strip_mailto(&::match_single_v_card_prefixed_field("ORGANIZER", &raw_text));
|
||||
let mut attendees: Vec<String> = ::match_v_card_prefixed_field("ATTENDEE", &raw_text);
|
||||
if attendees != null {
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < attendees.len() {
|
||||
{
|
||||
attendees[i] = ::strip_mailto(attendees[i]);
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
let description: String = ::match_single_v_card_prefixed_field("DESCRIPTION", &raw_text);
|
||||
let geo_string: String = ::match_single_v_card_prefixed_field("GEO", &raw_text);
|
||||
let mut latitude: f64;
|
||||
let mut longitude: f64;
|
||||
if geo_string == null {
|
||||
latitude = Double::NaN;
|
||||
longitude = Double::NaN;
|
||||
} else {
|
||||
let semicolon: i32 = geo_string.index_of(';');
|
||||
if semicolon < 0 {
|
||||
return null;
|
||||
}
|
||||
let tryResult1 = 0;
|
||||
'try1: loop {
|
||||
{
|
||||
latitude = Double::parse_double(&geo_string.substring(0, semicolon));
|
||||
longitude = Double::parse_double(&geo_string.substring(semicolon + 1));
|
||||
}
|
||||
break 'try1
|
||||
}
|
||||
match tryResult1 {
|
||||
catch ( ignored: &NumberFormatException) {
|
||||
return null;
|
||||
} 0 => break
|
||||
}
|
||||
|
||||
}
|
||||
let tryResult1 = 0;
|
||||
'try1: loop {
|
||||
{
|
||||
return CalendarParsedResult::new(&summary, &start, &end, &duration, &location, &organizer, &attendees, &description, latitude, longitude);
|
||||
}
|
||||
break 'try1
|
||||
}
|
||||
match tryResult1 {
|
||||
catch ( ignored: &IllegalArgumentException) {
|
||||
return null;
|
||||
} 0 => break
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fn match_single_v_card_prefixed_field( prefix: &CharSequence, raw_text: &String) -> String {
|
||||
let values: List<String> = VCardResultParser::match_single_v_card_prefixed_field(&prefix, &raw_text, true, false);
|
||||
return if values == null || values.is_empty() { null } else { values.get(0) };
|
||||
}
|
||||
|
||||
fn match_v_card_prefixed_field( prefix: &CharSequence, raw_text: &String) -> Vec<String> {
|
||||
let values: List<List<String>> = VCardResultParser::match_v_card_prefixed_field(&prefix, &raw_text, true, false);
|
||||
if values == null || values.is_empty() {
|
||||
return null;
|
||||
}
|
||||
let size: i32 = values.size();
|
||||
let mut result: [Option<String>; size] = [None; size];
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < size {
|
||||
{
|
||||
result[i] = values.get(i).get(0);
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
fn strip_mailto( s: &String) -> String {
|
||||
if s != null && (s.starts_with("mailto:") || s.starts_with("MAILTO:")) {
|
||||
s = s.substring(7);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
}
|
||||
|
||||
108
port_src/output/zxing/client/result/v_i_n_parsed_result.rs
Normal file
108
port_src/output/zxing/client/result/v_i_n_parsed_result.rs
Normal file
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* Copyright 2014 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::client::result;
|
||||
|
||||
/**
|
||||
* Represents a parsed result that encodes a Vehicle Identification Number (VIN).
|
||||
*/
|
||||
pub struct VINParsedResult {
|
||||
super: ParsedResult;
|
||||
|
||||
let vin: String;
|
||||
|
||||
let world_manufacturer_i_d: String;
|
||||
|
||||
let vehicle_descriptor_section: String;
|
||||
|
||||
let vehicle_identifier_section: String;
|
||||
|
||||
let country_code: String;
|
||||
|
||||
let vehicle_attributes: String;
|
||||
|
||||
let model_year: i32;
|
||||
|
||||
let plant_code: char;
|
||||
|
||||
let sequential_number: String;
|
||||
}
|
||||
|
||||
impl VINParsedResult {
|
||||
|
||||
pub fn new( vin: &String, world_manufacturer_i_d: &String, vehicle_descriptor_section: &String, vehicle_identifier_section: &String, country_code: &String, vehicle_attributes: &String, model_year: i32, plant_code: char, sequential_number: &String) -> VINParsedResult {
|
||||
super(ParsedResultType::VIN);
|
||||
let .vin = vin;
|
||||
let .worldManufacturerID = world_manufacturer_i_d;
|
||||
let .vehicleDescriptorSection = vehicle_descriptor_section;
|
||||
let .vehicleIdentifierSection = vehicle_identifier_section;
|
||||
let .countryCode = country_code;
|
||||
let .vehicleAttributes = vehicle_attributes;
|
||||
let .modelYear = model_year;
|
||||
let .plantCode = plant_code;
|
||||
let .sequentialNumber = sequential_number;
|
||||
}
|
||||
|
||||
pub fn get_v_i_n(&self) -> String {
|
||||
return self.vin;
|
||||
}
|
||||
|
||||
pub fn get_world_manufacturer_i_d(&self) -> String {
|
||||
return self.world_manufacturer_i_d;
|
||||
}
|
||||
|
||||
pub fn get_vehicle_descriptor_section(&self) -> String {
|
||||
return self.vehicle_descriptor_section;
|
||||
}
|
||||
|
||||
pub fn get_vehicle_identifier_section(&self) -> String {
|
||||
return self.vehicle_identifier_section;
|
||||
}
|
||||
|
||||
pub fn get_country_code(&self) -> String {
|
||||
return self.country_code;
|
||||
}
|
||||
|
||||
pub fn get_vehicle_attributes(&self) -> String {
|
||||
return self.vehicle_attributes;
|
||||
}
|
||||
|
||||
pub fn get_model_year(&self) -> i32 {
|
||||
return self.model_year;
|
||||
}
|
||||
|
||||
pub fn get_plant_code(&self) -> char {
|
||||
return self.plant_code;
|
||||
}
|
||||
|
||||
pub fn get_sequential_number(&self) -> String {
|
||||
return self.sequential_number;
|
||||
}
|
||||
|
||||
pub fn get_display_result(&self) -> String {
|
||||
let result: StringBuilder = StringBuilder::new(50);
|
||||
result.append(&self.world_manufacturer_i_d).append(' ');
|
||||
result.append(&self.vehicle_descriptor_section).append(' ');
|
||||
result.append(&self.vehicle_identifier_section).append('\n');
|
||||
if self.country_code != null {
|
||||
result.append(&self.country_code).append(' ');
|
||||
}
|
||||
result.append(self.model_year).append(' ');
|
||||
result.append(self.plant_code).append(' ');
|
||||
result.append(&self.sequential_number).append('\n');
|
||||
return result.to_string();
|
||||
}
|
||||
}
|
||||
|
||||
244
port_src/output/zxing/client/result/v_i_n_result_parser.rs
Normal file
244
port_src/output/zxing/client/result/v_i_n_result_parser.rs
Normal file
@@ -0,0 +1,244 @@
|
||||
/*
|
||||
* Copyright 2014 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::client::result;
|
||||
|
||||
/**
|
||||
* Detects a result that is likely a vehicle identification number.
|
||||
*
|
||||
* @author Sean Owen
|
||||
*/
|
||||
|
||||
const IOQ: Pattern = Pattern::compile("[IOQ]");
|
||||
|
||||
const AZ09: Pattern = Pattern::compile("[A-Z0-9]{17}");
|
||||
pub struct VINResultParser {
|
||||
super: ResultParser;
|
||||
}
|
||||
|
||||
impl VINResultParser {
|
||||
|
||||
pub fn parse(&self, result: &Result) -> VINParsedResult {
|
||||
if result.get_barcode_format() != BarcodeFormat::CODE_39 {
|
||||
return null;
|
||||
}
|
||||
let raw_text: String = result.get_text();
|
||||
raw_text = IOQ::matcher(&raw_text)::replace_all("")::trim();
|
||||
if !AZ09::matcher(&raw_text)::matches() {
|
||||
return null;
|
||||
}
|
||||
let tryResult1 = 0;
|
||||
'try1: loop {
|
||||
{
|
||||
if !::check_checksum(&raw_text) {
|
||||
return null;
|
||||
}
|
||||
let wmi: String = raw_text.substring(0, 3);
|
||||
return VINParsedResult::new(&raw_text, &wmi, &raw_text.substring(3, 9), &raw_text.substring(9, 17), &::country_code(&wmi), &raw_text.substring(3, 8), &::model_year(&raw_text.char_at(9)), &raw_text.char_at(10), &raw_text.substring(11));
|
||||
}
|
||||
break 'try1
|
||||
}
|
||||
match tryResult1 {
|
||||
catch ( iae: &IllegalArgumentException) {
|
||||
return null;
|
||||
} 0 => break
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fn check_checksum( vin: &CharSequence) -> bool {
|
||||
let mut sum: i32 = 0;
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < vin.length() {
|
||||
{
|
||||
sum += ::vin_position_weight(i + 1) * ::vin_char_value(&vin.char_at(i));
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
let check_char: char = vin.char_at(8);
|
||||
let expected_check_char: char = self.check_char(sum % 11);
|
||||
return check_char == expected_check_char;
|
||||
}
|
||||
|
||||
fn vin_char_value( c: char) -> i32 {
|
||||
if c >= 'A' && c <= 'I' {
|
||||
return (c - 'A') + 1;
|
||||
}
|
||||
if c >= 'J' && c <= 'R' {
|
||||
return (c - 'J') + 1;
|
||||
}
|
||||
if c >= 'S' && c <= 'Z' {
|
||||
return (c - 'S') + 2;
|
||||
}
|
||||
if c >= '0' && c <= '9' {
|
||||
return c - '0';
|
||||
}
|
||||
throw IllegalArgumentException::new();
|
||||
}
|
||||
|
||||
fn vin_position_weight( position: i32) -> i32 {
|
||||
if position >= 1 && position <= 7 {
|
||||
return 9 - position;
|
||||
}
|
||||
if position == 8 {
|
||||
return 10;
|
||||
}
|
||||
if position == 9 {
|
||||
return 0;
|
||||
}
|
||||
if position >= 10 && position <= 17 {
|
||||
return 19 - position;
|
||||
}
|
||||
throw IllegalArgumentException::new();
|
||||
}
|
||||
|
||||
fn check_char( remainder: i32) -> char {
|
||||
if remainder < 10 {
|
||||
return ('0' + remainder) as char;
|
||||
}
|
||||
if remainder == 10 {
|
||||
return 'X';
|
||||
}
|
||||
throw IllegalArgumentException::new();
|
||||
}
|
||||
|
||||
fn model_year( c: char) -> i32 {
|
||||
if c >= 'E' && c <= 'H' {
|
||||
return (c - 'E') + 1984;
|
||||
}
|
||||
if c >= 'J' && c <= 'N' {
|
||||
return (c - 'J') + 1988;
|
||||
}
|
||||
if c == 'P' {
|
||||
return 1993;
|
||||
}
|
||||
if c >= 'R' && c <= 'T' {
|
||||
return (c - 'R') + 1994;
|
||||
}
|
||||
if c >= 'V' && c <= 'Y' {
|
||||
return (c - 'V') + 1997;
|
||||
}
|
||||
if c >= '1' && c <= '9' {
|
||||
return (c - '1') + 2001;
|
||||
}
|
||||
if c >= 'A' && c <= 'D' {
|
||||
return (c - 'A') + 2010;
|
||||
}
|
||||
throw IllegalArgumentException::new();
|
||||
}
|
||||
|
||||
fn country_code( wmi: &CharSequence) -> String {
|
||||
let c1: char = wmi.char_at(0);
|
||||
let c2: char = wmi.char_at(1);
|
||||
match c1 {
|
||||
'1' =>
|
||||
{
|
||||
}
|
||||
'4' =>
|
||||
{
|
||||
}
|
||||
'5' =>
|
||||
{
|
||||
return "US";
|
||||
}
|
||||
'2' =>
|
||||
{
|
||||
return "CA";
|
||||
}
|
||||
'3' =>
|
||||
{
|
||||
if c2 >= 'A' && c2 <= 'W' {
|
||||
return "MX";
|
||||
}
|
||||
break;
|
||||
}
|
||||
'9' =>
|
||||
{
|
||||
if (c2 >= 'A' && c2 <= 'E') || (c2 >= '3' && c2 <= '9') {
|
||||
return "BR";
|
||||
}
|
||||
break;
|
||||
}
|
||||
'J' =>
|
||||
{
|
||||
if c2 >= 'A' && c2 <= 'T' {
|
||||
return "JP";
|
||||
}
|
||||
break;
|
||||
}
|
||||
'K' =>
|
||||
{
|
||||
if c2 >= 'L' && c2 <= 'R' {
|
||||
return "KO";
|
||||
}
|
||||
break;
|
||||
}
|
||||
'L' =>
|
||||
{
|
||||
return "CN";
|
||||
}
|
||||
'M' =>
|
||||
{
|
||||
if c2 >= 'A' && c2 <= 'E' {
|
||||
return "IN";
|
||||
}
|
||||
break;
|
||||
}
|
||||
'S' =>
|
||||
{
|
||||
if c2 >= 'A' && c2 <= 'M' {
|
||||
return "UK";
|
||||
}
|
||||
if c2 >= 'N' && c2 <= 'T' {
|
||||
return "DE";
|
||||
}
|
||||
break;
|
||||
}
|
||||
'V' =>
|
||||
{
|
||||
if c2 >= 'F' && c2 <= 'R' {
|
||||
return "FR";
|
||||
}
|
||||
if c2 >= 'S' && c2 <= 'W' {
|
||||
return "ES";
|
||||
}
|
||||
break;
|
||||
}
|
||||
'W' =>
|
||||
{
|
||||
return "DE";
|
||||
}
|
||||
'X' =>
|
||||
{
|
||||
if c2 == '0' || (c2 >= '3' && c2 <= '9') {
|
||||
return "RU";
|
||||
}
|
||||
break;
|
||||
}
|
||||
'Z' =>
|
||||
{
|
||||
if c2 >= 'A' && c2 <= 'R' {
|
||||
return "IT";
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
106
port_src/output/zxing/client/result/wifi_parsed_result.rs
Normal file
106
port_src/output/zxing/client/result/wifi_parsed_result.rs
Normal file
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
* 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::client::result;
|
||||
|
||||
/**
|
||||
* Represents a parsed result that encodes wifi network information, like SSID and password.
|
||||
*
|
||||
* @author Vikram Aggarwal
|
||||
*/
|
||||
pub struct WifiParsedResult {
|
||||
super: ParsedResult;
|
||||
|
||||
let ssid: String;
|
||||
|
||||
let network_encryption: String;
|
||||
|
||||
let password: String;
|
||||
|
||||
let hidden: bool;
|
||||
|
||||
let identity: String;
|
||||
|
||||
let anonymous_identity: String;
|
||||
|
||||
let eap_method: String;
|
||||
|
||||
let phase2_method: String;
|
||||
}
|
||||
|
||||
impl WifiParsedResult {
|
||||
|
||||
pub fn new( network_encryption: &String, ssid: &String, password: &String) -> WifiParsedResult {
|
||||
this(&network_encryption, &ssid, &password, false);
|
||||
}
|
||||
|
||||
pub fn new( network_encryption: &String, ssid: &String, password: &String, hidden: bool) -> WifiParsedResult {
|
||||
this(&network_encryption, &ssid, &password, hidden, null, null, null, null);
|
||||
}
|
||||
|
||||
pub fn new( network_encryption: &String, ssid: &String, password: &String, hidden: bool, identity: &String, anonymous_identity: &String, eap_method: &String, phase2_method: &String) -> WifiParsedResult {
|
||||
super(ParsedResultType::WIFI);
|
||||
let .ssid = ssid;
|
||||
let .networkEncryption = network_encryption;
|
||||
let .password = password;
|
||||
let .hidden = hidden;
|
||||
let .identity = identity;
|
||||
let .anonymousIdentity = anonymous_identity;
|
||||
let .eapMethod = eap_method;
|
||||
let .phase2Method = phase2_method;
|
||||
}
|
||||
|
||||
pub fn get_ssid(&self) -> String {
|
||||
return self.ssid;
|
||||
}
|
||||
|
||||
pub fn get_network_encryption(&self) -> String {
|
||||
return self.network_encryption;
|
||||
}
|
||||
|
||||
pub fn get_password(&self) -> String {
|
||||
return self.password;
|
||||
}
|
||||
|
||||
pub fn is_hidden(&self) -> bool {
|
||||
return self.hidden;
|
||||
}
|
||||
|
||||
pub fn get_identity(&self) -> String {
|
||||
return self.identity;
|
||||
}
|
||||
|
||||
pub fn get_anonymous_identity(&self) -> String {
|
||||
return self.anonymous_identity;
|
||||
}
|
||||
|
||||
pub fn get_eap_method(&self) -> String {
|
||||
return self.eap_method;
|
||||
}
|
||||
|
||||
pub fn get_phase2_method(&self) -> String {
|
||||
return self.phase2_method;
|
||||
}
|
||||
|
||||
pub fn get_display_result(&self) -> String {
|
||||
let result: StringBuilder = StringBuilder::new(80);
|
||||
maybe_append(&self.ssid, &result);
|
||||
maybe_append(&self.network_encryption, &result);
|
||||
maybe_append(&self.password, &result);
|
||||
maybe_append(&Boolean::to_string(self.hidden), &result);
|
||||
return result.to_string();
|
||||
}
|
||||
}
|
||||
|
||||
59
port_src/output/zxing/client/result/wifi_result_parser.rs
Normal file
59
port_src/output/zxing/client/result/wifi_result_parser.rs
Normal file
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* 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::client::result;
|
||||
|
||||
pub struct WifiResultParser {
|
||||
super: ResultParser;
|
||||
}
|
||||
|
||||
impl WifiResultParser {
|
||||
|
||||
pub fn parse(&self, result: &Result) -> WifiParsedResult {
|
||||
let raw_text: String = get_massaged_text(result);
|
||||
if !raw_text.starts_with("WIFI:") {
|
||||
return null;
|
||||
}
|
||||
raw_text = raw_text.substring(&"WIFI:".length());
|
||||
let ssid: String = match_single_prefixed_field("S:", &raw_text, ';', false);
|
||||
if ssid == null || ssid.is_empty() {
|
||||
return null;
|
||||
}
|
||||
let pass: String = match_single_prefixed_field("P:", &raw_text, ';', false);
|
||||
let mut type: String = match_single_prefixed_field("T:", &raw_text, ';', false);
|
||||
if type == null {
|
||||
type = "nopass";
|
||||
}
|
||||
// Unfortunately, in the past, H: was not just used for boolean 'hidden', but 'phase 2 method'.
|
||||
// To try to retain backwards compatibility, we set one or the other based on whether the string
|
||||
// is 'true' or 'false':
|
||||
let mut hidden: bool = false;
|
||||
let phase2_method: String = match_single_prefixed_field("PH2:", &raw_text, ';', false);
|
||||
let h_value: String = match_single_prefixed_field("H:", &raw_text, ';', false);
|
||||
if h_value != null {
|
||||
// If PH2 was specified separately, or if the value is clearly boolean, interpret it as 'hidden'
|
||||
if phase2_method != null || "true".equals_ignore_case(&h_value) || "false".equals_ignore_case(&h_value) {
|
||||
hidden = Boolean::parse_boolean(&h_value);
|
||||
} else {
|
||||
phase2_method = h_value;
|
||||
}
|
||||
}
|
||||
let identity: String = match_single_prefixed_field("I:", &raw_text, ';', false);
|
||||
let anonymous_identity: String = match_single_prefixed_field("A:", &raw_text, ';', false);
|
||||
let eap_method: String = match_single_prefixed_field("E:", &raw_text, ';', false);
|
||||
return WifiParsedResult::new(&type, &ssid, &pass, hidden, &identity, &anonymous_identity, &eap_method, &phase2_method);
|
||||
}
|
||||
}
|
||||
|
||||
436
port_src/output/zxing/common/bit_array.rs
Normal file
436
port_src/output/zxing/common/bit_array.rs
Normal file
@@ -0,0 +1,436 @@
|
||||
/*
|
||||
* 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::common;
|
||||
|
||||
/**
|
||||
* <p>A simple, fast array of bits, represented compactly by an array of ints internally.</p>
|
||||
*
|
||||
* @author Sean Owen
|
||||
*/
|
||||
|
||||
const EMPTY_BITS;
|
||||
|
||||
const LOAD_FACTOR: f32 = 0.75f;
|
||||
#[derive(Cloneable)]
|
||||
pub struct BitArray {
|
||||
|
||||
let mut bits: Vec<i32>;
|
||||
|
||||
let mut size: i32;
|
||||
}
|
||||
|
||||
impl BitArray {
|
||||
|
||||
pub fn new() -> BitArray {
|
||||
let .size = 0;
|
||||
let .bits = EMPTY_BITS;
|
||||
}
|
||||
|
||||
pub fn new( size: i32) -> BitArray {
|
||||
let .size = size;
|
||||
let .bits = ::make_array(size);
|
||||
}
|
||||
|
||||
// For testing only
|
||||
fn new( bits: &Vec<i32>, size: i32) -> BitArray {
|
||||
let .bits = bits;
|
||||
let .size = size;
|
||||
}
|
||||
|
||||
pub fn get_size(&self) -> i32 {
|
||||
return self.size;
|
||||
}
|
||||
|
||||
pub fn get_size_in_bytes(&self) -> i32 {
|
||||
return (self.size + 7) / 8;
|
||||
}
|
||||
|
||||
fn ensure_capacity(&self, new_size: i32) {
|
||||
if new_size > self.bits.len() * 32 {
|
||||
let new_bits: Vec<i32> = ::make_array(Math::ceil(new_size / LOAD_FACTOR) as i32);
|
||||
System::arraycopy(&self.bits, 0, &new_bits, 0, self.bits.len());
|
||||
self.bits = new_bits;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param i bit to get
|
||||
* @return true iff bit i is set
|
||||
*/
|
||||
pub fn get(&self, i: i32) -> bool {
|
||||
return (self.bits[i / 32] & (1 << (i & 0x1F))) != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets bit i.
|
||||
*
|
||||
* @param i bit to set
|
||||
*/
|
||||
pub fn set(&self, i: i32) {
|
||||
self.bits[i / 32] |= 1 << (i & 0x1F);
|
||||
}
|
||||
|
||||
/**
|
||||
* Flips bit i.
|
||||
*
|
||||
* @param i bit to set
|
||||
*/
|
||||
pub fn flip(&self, i: i32) {
|
||||
self.bits[i / 32] ^= 1 << (i & 0x1F);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param from first bit to check
|
||||
* @return index of first bit that is set, starting from the given index, or size if none are set
|
||||
* at or beyond this given index
|
||||
* @see #getNextUnset(int)
|
||||
*/
|
||||
pub fn get_next_set(&self, from: i32) -> i32 {
|
||||
if from >= self.size {
|
||||
return self.size;
|
||||
}
|
||||
let bits_offset: i32 = from / 32;
|
||||
let current_bits: i32 = self.bits[bits_offset];
|
||||
// mask off lesser bits first
|
||||
current_bits &= -(1 << (from & 0x1F));
|
||||
while current_bits == 0 {
|
||||
if bits_offset += 1 == self.bits.len() {
|
||||
return self.size;
|
||||
}
|
||||
current_bits = self.bits[bits_offset];
|
||||
}
|
||||
let result: i32 = (bits_offset * 32) + Integer::number_of_trailing_zeros(current_bits);
|
||||
return Math::min(result, self.size);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param from index to start looking for unset bit
|
||||
* @return index of next unset bit, or {@code size} if none are unset until the end
|
||||
* @see #getNextSet(int)
|
||||
*/
|
||||
pub fn get_next_unset(&self, from: i32) -> i32 {
|
||||
if from >= self.size {
|
||||
return self.size;
|
||||
}
|
||||
let bits_offset: i32 = from / 32;
|
||||
let current_bits: i32 = ~self.bits[bits_offset];
|
||||
// mask off lesser bits first
|
||||
current_bits &= -(1 << (from & 0x1F));
|
||||
while current_bits == 0 {
|
||||
if bits_offset += 1 == self.bits.len() {
|
||||
return self.size;
|
||||
}
|
||||
current_bits = ~self.bits[bits_offset];
|
||||
}
|
||||
let result: i32 = (bits_offset * 32) + Integer::number_of_trailing_zeros(current_bits);
|
||||
return Math::min(result, self.size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a block of 32 bits, starting at bit i.
|
||||
*
|
||||
* @param i first bit to set
|
||||
* @param newBits the new value of the next 32 bits. Note again that the least-significant bit
|
||||
* corresponds to bit i, the next-least-significant to i+1, and so on.
|
||||
*/
|
||||
pub fn set_bulk(&self, i: i32, new_bits: i32) {
|
||||
self.bits[i / 32] = new_bits;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a range of bits.
|
||||
*
|
||||
* @param start start of range, inclusive.
|
||||
* @param end end of range, exclusive
|
||||
*/
|
||||
pub fn set_range(&self, start: i32, end: i32) {
|
||||
if end < start || start < 0 || end > self.size {
|
||||
throw IllegalArgumentException::new();
|
||||
}
|
||||
if end == start {
|
||||
return;
|
||||
}
|
||||
// will be easier to treat this as the last actually set bit -- inclusive
|
||||
end -= 1;
|
||||
let first_int: i32 = start / 32;
|
||||
let last_int: i32 = end / 32;
|
||||
{
|
||||
let mut i: i32 = first_int;
|
||||
while i <= last_int {
|
||||
{
|
||||
let first_bit: i32 = if i > first_int { 0 } else { start & 0x1F };
|
||||
let last_bit: i32 = if i < last_int { 31 } else { end & 0x1F };
|
||||
// Ones from firstBit to lastBit, inclusive
|
||||
let mask: i32 = (2 << last_bit) - (1 << first_bit);
|
||||
self.bits[i] |= mask;
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears all bits (sets to false).
|
||||
*/
|
||||
pub fn clear(&self) {
|
||||
let max: i32 = self.bits.len();
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < max {
|
||||
{
|
||||
self.bits[i] = 0;
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Efficient method to check if a range of bits is set, or not set.
|
||||
*
|
||||
* @param start start of range, inclusive.
|
||||
* @param end end of range, exclusive
|
||||
* @param value if true, checks that bits in range are set, otherwise checks that they are not set
|
||||
* @return true iff all bits are set or not set in range, according to value argument
|
||||
* @throws IllegalArgumentException if end is less than start or the range is not contained in the array
|
||||
*/
|
||||
pub fn is_range(&self, start: i32, end: i32, value: bool) -> bool {
|
||||
if end < start || start < 0 || end > self.size {
|
||||
throw IllegalArgumentException::new();
|
||||
}
|
||||
if end == start {
|
||||
// empty range matches
|
||||
return true;
|
||||
}
|
||||
// will be easier to treat this as the last actually set bit -- inclusive
|
||||
end -= 1;
|
||||
let first_int: i32 = start / 32;
|
||||
let last_int: i32 = end / 32;
|
||||
{
|
||||
let mut i: i32 = first_int;
|
||||
while i <= last_int {
|
||||
{
|
||||
let first_bit: i32 = if i > first_int { 0 } else { start & 0x1F };
|
||||
let last_bit: i32 = if i < last_int { 31 } else { end & 0x1F };
|
||||
// Ones from firstBit to lastBit, inclusive
|
||||
let mask: i32 = (2 << last_bit) - (1 << first_bit);
|
||||
// equals the mask, or we're looking for 0s and the masked portion is not all 0s
|
||||
if (self.bits[i] & mask) != ( if value { mask } else { 0 }) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
pub fn append_bit(&self, bit: bool) {
|
||||
self.ensure_capacity(self.size + 1);
|
||||
if bit {
|
||||
self.bits[self.size / 32] |= 1 << (self.size & 0x1F);
|
||||
}
|
||||
self.size += 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends the least-significant bits, from value, in order from most-significant to
|
||||
* least-significant. For example, appending 6 bits from 0x000001E will append the bits
|
||||
* 0, 1, 1, 1, 1, 0 in that order.
|
||||
*
|
||||
* @param value {@code int} containing bits to append
|
||||
* @param numBits bits from value to append
|
||||
*/
|
||||
pub fn append_bits(&self, value: i32, num_bits: i32) {
|
||||
if num_bits < 0 || num_bits > 32 {
|
||||
throw IllegalArgumentException::new("Num bits must be between 0 and 32");
|
||||
}
|
||||
let next_size: i32 = self.size;
|
||||
self.ensure_capacity(next_size + num_bits);
|
||||
{
|
||||
let num_bits_left: i32 = num_bits - 1;
|
||||
while num_bits_left >= 0 {
|
||||
{
|
||||
if (value & (1 << num_bits_left)) != 0 {
|
||||
self.bits[next_size / 32] |= 1 << (next_size & 0x1F);
|
||||
}
|
||||
next_size += 1;
|
||||
}
|
||||
num_bits_left -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
self.size = next_size;
|
||||
}
|
||||
|
||||
pub fn append_bit_array(&self, other: &BitArray) {
|
||||
let other_size: i32 = other.size;
|
||||
self.ensure_capacity(self.size + other_size);
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < other_size {
|
||||
{
|
||||
self.append_bit(&other.get(i));
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
pub fn xor(&self, other: &BitArray) {
|
||||
if self.size != other.size {
|
||||
throw IllegalArgumentException::new("Sizes don't match");
|
||||
}
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < self.bits.len() {
|
||||
{
|
||||
// The last int could be incomplete (i.e. not have 32 bits in
|
||||
// it) but there is no problem since 0 XOR 0 == 0.
|
||||
self.bits[i] ^= other.bits[i];
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param bitOffset first bit to start writing
|
||||
* @param array array to write into. Bytes are written most-significant byte first. This is the opposite
|
||||
* of the internal representation, which is exposed by {@link #getBitArray()}
|
||||
* @param offset position in array to start writing
|
||||
* @param numBytes how many bytes to write
|
||||
*/
|
||||
pub fn to_bytes(&self, bit_offset: i32, array: &Vec<i8>, offset: i32, num_bytes: i32) {
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < num_bytes {
|
||||
{
|
||||
let the_byte: i32 = 0;
|
||||
{
|
||||
let mut j: i32 = 0;
|
||||
while j < 8 {
|
||||
{
|
||||
if self.get(bit_offset) {
|
||||
the_byte |= 1 << (7 - j);
|
||||
}
|
||||
bit_offset += 1;
|
||||
}
|
||||
j += 1;
|
||||
}
|
||||
}
|
||||
|
||||
array[offset + i] = the_byte as i8;
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @return underlying array of ints. The first element holds the first 32 bits, and the least
|
||||
* significant bit is bit 0.
|
||||
*/
|
||||
pub fn get_bit_array(&self) -> Vec<i32> {
|
||||
return self.bits;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverses all bits in the array.
|
||||
*/
|
||||
pub fn reverse(&self) {
|
||||
let new_bits: [i32; self.bits.len()] = [0; self.bits.len()];
|
||||
// reverse all int's first
|
||||
let mut len: i32 = (self.size - 1) / 32;
|
||||
let old_bits_len: i32 = len + 1;
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < old_bits_len {
|
||||
{
|
||||
new_bits[len - i] = Integer::reverse(self.bits[i]);
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
// now correct the int's if the bit size isn't a multiple of 32
|
||||
if self.size != old_bits_len * 32 {
|
||||
let left_offset: i32 = old_bits_len * 32 - self.size;
|
||||
let current_int: i32 = new_bits[0] >> /* >>> */ left_offset;
|
||||
{
|
||||
let mut i: i32 = 1;
|
||||
while i < old_bits_len {
|
||||
{
|
||||
let next_int: i32 = new_bits[i];
|
||||
current_int |= next_int << (32 - left_offset);
|
||||
new_bits[i - 1] = current_int;
|
||||
current_int = next_int >> /* >>> */ left_offset;
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
new_bits[old_bits_len - 1] = current_int;
|
||||
}
|
||||
self.bits = new_bits;
|
||||
}
|
||||
|
||||
fn make_array( size: i32) -> Vec<i32> {
|
||||
return : [i32; (size + 31) / 32] = [0; (size + 31) / 32];
|
||||
}
|
||||
|
||||
pub fn equals(&self, o: &Object) -> bool {
|
||||
if !(o instanceof BitArray) {
|
||||
return false;
|
||||
}
|
||||
let other: BitArray = o as BitArray;
|
||||
return self.size == other.size && Arrays::equals(&self.bits, other.bits);
|
||||
}
|
||||
|
||||
pub fn hash_code(&self) -> i32 {
|
||||
return 31 * self.size + Arrays::hash_code(&self.bits);
|
||||
}
|
||||
|
||||
pub fn to_string(&self) -> String {
|
||||
let result: StringBuilder = StringBuilder::new(self.size + (self.size / 8) + 1);
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < self.size {
|
||||
{
|
||||
if (i & 0x07) == 0 {
|
||||
result.append(' ');
|
||||
}
|
||||
result.append( if self.get(i) { 'X' } else { '.' });
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
return result.to_string();
|
||||
}
|
||||
|
||||
pub fn clone(&self) -> BitArray {
|
||||
return BitArray::new(&self.bits.clone(), self.size);
|
||||
}
|
||||
}
|
||||
|
||||
652
port_src/output/zxing/common/bit_matrix.rs
Normal file
652
port_src/output/zxing/common/bit_matrix.rs
Normal file
@@ -0,0 +1,652 @@
|
||||
/*
|
||||
* 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::common;
|
||||
|
||||
/**
|
||||
* <p>Represents a 2D matrix of bits. In function arguments below, and throughout the common
|
||||
* module, x is the column position, and y is the row position. The ordering is always x, y.
|
||||
* The origin is at the top-left.</p>
|
||||
*
|
||||
* <p>Internally the bits are represented in a 1-D array of 32-bit ints. However, each row begins
|
||||
* with a new int. This is done intentionally so that we can copy out a row into a BitArray very
|
||||
* efficiently.</p>
|
||||
*
|
||||
* <p>The ordering of bits is row-major. Within each int, the least significant bits are used first,
|
||||
* meaning they represent lower x values. This is compatible with BitArray's implementation.</p>
|
||||
*
|
||||
* @author Sean Owen
|
||||
* @author dswitkin@google.com (Daniel Switkin)
|
||||
*/
|
||||
#[derive(Cloneable)]
|
||||
pub struct BitMatrix {
|
||||
|
||||
let mut width: i32;
|
||||
|
||||
let mut height: i32;
|
||||
|
||||
let row_size: i32;
|
||||
|
||||
let mut bits: Vec<i32>;
|
||||
}
|
||||
|
||||
impl BitMatrix {
|
||||
|
||||
/**
|
||||
* Creates an empty square {@code BitMatrix}.
|
||||
*
|
||||
* @param dimension height and width
|
||||
*/
|
||||
pub fn new( dimension: i32) -> BitMatrix {
|
||||
this(dimension, dimension);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an empty {@code BitMatrix}.
|
||||
*
|
||||
* @param width bit matrix width
|
||||
* @param height bit matrix height
|
||||
*/
|
||||
pub fn new( width: i32, height: i32) -> BitMatrix {
|
||||
if width < 1 || height < 1 {
|
||||
throw IllegalArgumentException::new("Both dimensions must be greater than 0");
|
||||
}
|
||||
let .width = width;
|
||||
let .height = height;
|
||||
let .rowSize = (width + 31) / 32;
|
||||
bits = : [i32; row_size * height] = [0; row_size * height];
|
||||
}
|
||||
|
||||
fn new( width: i32, height: i32, row_size: i32, bits: &Vec<i32>) -> BitMatrix {
|
||||
let .width = width;
|
||||
let .height = height;
|
||||
let .rowSize = row_size;
|
||||
let .bits = bits;
|
||||
}
|
||||
|
||||
/**
|
||||
* Interprets a 2D array of booleans as a {@code BitMatrix}, where "true" means an "on" bit.
|
||||
*
|
||||
* @param image bits of the image, as a row-major 2D array. Elements are arrays representing rows
|
||||
* @return {@code BitMatrix} representation of image
|
||||
*/
|
||||
pub fn parse( image: &Vec<Vec<bool>>) -> BitMatrix {
|
||||
let height: i32 = image.len();
|
||||
let width: i32 = image[0].len();
|
||||
let bits: BitMatrix = BitMatrix::new(width, height);
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < height {
|
||||
{
|
||||
let image_i: Vec<bool> = image[i];
|
||||
{
|
||||
let mut j: i32 = 0;
|
||||
while j < width {
|
||||
{
|
||||
if image_i[j] {
|
||||
bits.set(j, i);
|
||||
}
|
||||
}
|
||||
j += 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
return bits;
|
||||
}
|
||||
|
||||
pub fn parse( string_representation: &String, set_string: &String, unset_string: &String) -> BitMatrix {
|
||||
if string_representation == null {
|
||||
throw IllegalArgumentException::new();
|
||||
}
|
||||
let mut bits: [bool; string_representation.length()] = [false; string_representation.length()];
|
||||
let bits_pos: i32 = 0;
|
||||
let row_start_pos: i32 = 0;
|
||||
let row_length: i32 = -1;
|
||||
let n_rows: i32 = 0;
|
||||
let mut pos: i32 = 0;
|
||||
while pos < string_representation.length() {
|
||||
if string_representation.char_at(pos) == '\n' || string_representation.char_at(pos) == '\r' {
|
||||
if bits_pos > row_start_pos {
|
||||
if row_length == -1 {
|
||||
row_length = bits_pos - row_start_pos;
|
||||
} else if bits_pos - row_start_pos != row_length {
|
||||
throw IllegalArgumentException::new("row lengths do not match");
|
||||
}
|
||||
row_start_pos = bits_pos;
|
||||
n_rows += 1;
|
||||
}
|
||||
pos += 1;
|
||||
} else if string_representation.starts_with(&set_string, pos) {
|
||||
pos += set_string.length();
|
||||
bits[bits_pos] = true;
|
||||
bits_pos += 1;
|
||||
} else if string_representation.starts_with(&unset_string, pos) {
|
||||
pos += unset_string.length();
|
||||
bits[bits_pos] = false;
|
||||
bits_pos += 1;
|
||||
} else {
|
||||
throw IllegalArgumentException::new(format!("illegal character encountered: {}", string_representation.substring(pos)));
|
||||
}
|
||||
}
|
||||
// no EOL at end?
|
||||
if bits_pos > row_start_pos {
|
||||
if row_length == -1 {
|
||||
row_length = bits_pos - row_start_pos;
|
||||
} else if bits_pos - row_start_pos != row_length {
|
||||
throw IllegalArgumentException::new("row lengths do not match");
|
||||
}
|
||||
n_rows += 1;
|
||||
}
|
||||
let matrix: BitMatrix = BitMatrix::new(row_length, n_rows);
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < bits_pos {
|
||||
{
|
||||
if bits[i] {
|
||||
matrix.set(i % row_length, i / row_length);
|
||||
}
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
return matrix;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Gets the requested bit, where true means black.</p>
|
||||
*
|
||||
* @param x The horizontal component (i.e. which column)
|
||||
* @param y The vertical component (i.e. which row)
|
||||
* @return value of given bit in matrix
|
||||
*/
|
||||
pub fn get(&self, x: i32, y: i32) -> bool {
|
||||
let offset: i32 = y * self.row_size + (x / 32);
|
||||
return ((self.bits[offset] >> /* >>> */ (x & 0x1f)) & 1) != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Sets the given bit to true.</p>
|
||||
*
|
||||
* @param x The horizontal component (i.e. which column)
|
||||
* @param y The vertical component (i.e. which row)
|
||||
*/
|
||||
pub fn set(&self, x: i32, y: i32) {
|
||||
let mut offset: i32 = y * self.row_size + (x / 32);
|
||||
self.bits[offset] |= 1 << (x & 0x1f);
|
||||
}
|
||||
|
||||
pub fn unset(&self, x: i32, y: i32) {
|
||||
let mut offset: i32 = y * self.row_size + (x / 32);
|
||||
self.bits[offset] &= ~(1 << (x & 0x1f));
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Flips the given bit.</p>
|
||||
*
|
||||
* @param x The horizontal component (i.e. which column)
|
||||
* @param y The vertical component (i.e. which row)
|
||||
*/
|
||||
pub fn flip(&self, x: i32, y: i32) {
|
||||
let mut offset: i32 = y * self.row_size + (x / 32);
|
||||
self.bits[offset] ^= 1 << (x & 0x1f);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Flips every bit in the matrix.</p>
|
||||
*/
|
||||
pub fn flip(&self) {
|
||||
let max: i32 = self.bits.len();
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < max {
|
||||
{
|
||||
self.bits[i] = ~self.bits[i];
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Exclusive-or (XOR): Flip the bit in this {@code BitMatrix} if the corresponding
|
||||
* mask bit is set.
|
||||
*
|
||||
* @param mask XOR mask
|
||||
*/
|
||||
pub fn xor(&self, mask: &BitMatrix) {
|
||||
if self.width != mask.width || self.height != mask.height || self.row_size != mask.rowSize {
|
||||
throw IllegalArgumentException::new("input matrix dimensions do not match");
|
||||
}
|
||||
let row_array: BitArray = BitArray::new(self.width);
|
||||
{
|
||||
let mut y: i32 = 0;
|
||||
while y < self.height {
|
||||
{
|
||||
let mut offset: i32 = y * self.row_size;
|
||||
let row: Vec<i32> = mask.get_row(y, row_array).get_bit_array();
|
||||
{
|
||||
let mut x: i32 = 0;
|
||||
while x < self.row_size {
|
||||
{
|
||||
self.bits[offset + x] ^= row[x];
|
||||
}
|
||||
x += 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
y += 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears all bits (sets to false).
|
||||
*/
|
||||
pub fn clear(&self) {
|
||||
let max: i32 = self.bits.len();
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < max {
|
||||
{
|
||||
self.bits[i] = 0;
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Sets a square region of the bit matrix to true.</p>
|
||||
*
|
||||
* @param left The horizontal position to begin at (inclusive)
|
||||
* @param top The vertical position to begin at (inclusive)
|
||||
* @param width The width of the region
|
||||
* @param height The height of the region
|
||||
*/
|
||||
pub fn set_region(&self, left: i32, top: i32, width: i32, height: i32) {
|
||||
if top < 0 || left < 0 {
|
||||
throw IllegalArgumentException::new("Left and top must be nonnegative");
|
||||
}
|
||||
if height < 1 || width < 1 {
|
||||
throw IllegalArgumentException::new("Height and width must be at least 1");
|
||||
}
|
||||
let right: i32 = left + width;
|
||||
let bottom: i32 = top + height;
|
||||
if bottom > self.height || right > self.width {
|
||||
throw IllegalArgumentException::new("The region must fit inside the matrix");
|
||||
}
|
||||
{
|
||||
let mut y: i32 = top;
|
||||
while y < bottom {
|
||||
{
|
||||
let mut offset: i32 = y * self.row_size;
|
||||
{
|
||||
let mut x: i32 = left;
|
||||
while x < right {
|
||||
{
|
||||
self.bits[offset + (x / 32)] |= 1 << (x & 0x1f);
|
||||
}
|
||||
x += 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
y += 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* A fast method to retrieve one row of data from the matrix as a BitArray.
|
||||
*
|
||||
* @param y The row to retrieve
|
||||
* @param row An optional caller-allocated BitArray, will be allocated if null or too small
|
||||
* @return The resulting BitArray - this reference should always be used even when passing
|
||||
* your own row
|
||||
*/
|
||||
pub fn get_row(&self, y: i32, row: &BitArray) -> BitArray {
|
||||
if row == null || row.get_size() < self.width {
|
||||
row = BitArray::new(self.width);
|
||||
} else {
|
||||
row.clear();
|
||||
}
|
||||
let offset: i32 = y * self.row_size;
|
||||
{
|
||||
let mut x: i32 = 0;
|
||||
while x < self.row_size {
|
||||
{
|
||||
row.set_bulk(x * 32, self.bits[offset + x]);
|
||||
}
|
||||
x += 1;
|
||||
}
|
||||
}
|
||||
|
||||
return row;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param y row to set
|
||||
* @param row {@link BitArray} to copy from
|
||||
*/
|
||||
pub fn set_row(&self, y: i32, row: &BitArray) {
|
||||
System::arraycopy(&row.get_bit_array(), 0, &self.bits, y * self.row_size, self.row_size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Modifies this {@code BitMatrix} to represent the same but rotated the given degrees (0, 90, 180, 270)
|
||||
*
|
||||
* @param degrees number of degrees to rotate through counter-clockwise (0, 90, 180, 270)
|
||||
*/
|
||||
pub fn rotate(&self, degrees: i32) {
|
||||
match degrees % 360 {
|
||||
0 =>
|
||||
{
|
||||
return;
|
||||
}
|
||||
90 =>
|
||||
{
|
||||
self.rotate90();
|
||||
return;
|
||||
}
|
||||
180 =>
|
||||
{
|
||||
self.rotate180();
|
||||
return;
|
||||
}
|
||||
270 =>
|
||||
{
|
||||
self.rotate90();
|
||||
self.rotate180();
|
||||
return;
|
||||
}
|
||||
}
|
||||
throw IllegalArgumentException::new("degrees must be a multiple of 0, 90, 180, or 270");
|
||||
}
|
||||
|
||||
/**
|
||||
* Modifies this {@code BitMatrix} to represent the same but rotated 180 degrees
|
||||
*/
|
||||
pub fn rotate180(&self) {
|
||||
let top_row: BitArray = BitArray::new(self.width);
|
||||
let bottom_row: BitArray = BitArray::new(self.width);
|
||||
let max_height: i32 = (self.height + 1) / 2;
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < max_height {
|
||||
{
|
||||
top_row = self.get_row(i, top_row);
|
||||
let bottom_row_index: i32 = self.height - 1 - i;
|
||||
bottom_row = self.get_row(bottom_row_index, bottom_row);
|
||||
top_row.reverse();
|
||||
bottom_row.reverse();
|
||||
self.set_row(i, bottom_row);
|
||||
self.set_row(bottom_row_index, top_row);
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Modifies this {@code BitMatrix} to represent the same but rotated 90 degrees counterclockwise
|
||||
*/
|
||||
pub fn rotate90(&self) {
|
||||
let new_width: i32 = self.height;
|
||||
let new_height: i32 = self.width;
|
||||
let new_row_size: i32 = (new_width + 31) / 32;
|
||||
let new_bits: [i32; new_row_size * new_height] = [0; new_row_size * new_height];
|
||||
{
|
||||
let mut y: i32 = 0;
|
||||
while y < self.height {
|
||||
{
|
||||
{
|
||||
let mut x: i32 = 0;
|
||||
while x < self.width {
|
||||
{
|
||||
let offset: i32 = y * self.row_size + (x / 32);
|
||||
if ((self.bits[offset] >> /* >>> */ (x & 0x1f)) & 1) != 0 {
|
||||
let new_offset: i32 = (new_height - 1 - x) * new_row_size + (y / 32);
|
||||
new_bits[new_offset] |= 1 << (y & 0x1f);
|
||||
}
|
||||
}
|
||||
x += 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
y += 1;
|
||||
}
|
||||
}
|
||||
|
||||
self.width = new_width;
|
||||
self.height = new_height;
|
||||
self.row_size = new_row_size;
|
||||
self.bits = new_bits;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is useful in detecting the enclosing rectangle of a 'pure' barcode.
|
||||
*
|
||||
* @return {@code left,top,width,height} enclosing rectangle of all 1 bits, or null if it is all white
|
||||
*/
|
||||
pub fn get_enclosing_rectangle(&self) -> Vec<i32> {
|
||||
let mut left: i32 = self.width;
|
||||
let mut top: i32 = self.height;
|
||||
let mut right: i32 = -1;
|
||||
let mut bottom: i32 = -1;
|
||||
{
|
||||
let mut y: i32 = 0;
|
||||
while y < self.height {
|
||||
{
|
||||
{
|
||||
let mut x32: i32 = 0;
|
||||
while x32 < self.row_size {
|
||||
{
|
||||
let the_bits: i32 = self.bits[y * self.row_size + x32];
|
||||
if the_bits != 0 {
|
||||
if y < top {
|
||||
top = y;
|
||||
}
|
||||
if y > bottom {
|
||||
bottom = y;
|
||||
}
|
||||
if x32 * 32 < left {
|
||||
let mut bit: i32 = 0;
|
||||
while (the_bits << (31 - bit)) == 0 {
|
||||
bit += 1;
|
||||
}
|
||||
if (x32 * 32 + bit) < left {
|
||||
left = x32 * 32 + bit;
|
||||
}
|
||||
}
|
||||
if x32 * 32 + 31 > right {
|
||||
let mut bit: i32 = 31;
|
||||
while (the_bits >> /* >>> */ bit) == 0 {
|
||||
bit -= 1;
|
||||
}
|
||||
if (x32 * 32 + bit) > right {
|
||||
right = x32 * 32 + bit;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
x32 += 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
y += 1;
|
||||
}
|
||||
}
|
||||
|
||||
if right < left || bottom < top {
|
||||
return null;
|
||||
}
|
||||
return : vec![i32; 4] = vec![left, top, right - left + 1, bottom - top + 1, ]
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is useful in detecting a corner of a 'pure' barcode.
|
||||
*
|
||||
* @return {@code x,y} coordinate of top-left-most 1 bit, or null if it is all white
|
||||
*/
|
||||
pub fn get_top_left_on_bit(&self) -> Vec<i32> {
|
||||
let bits_offset: i32 = 0;
|
||||
while bits_offset < self.bits.len() && self.bits[bits_offset] == 0 {
|
||||
bits_offset += 1;
|
||||
}
|
||||
if bits_offset == self.bits.len() {
|
||||
return null;
|
||||
}
|
||||
let y: i32 = bits_offset / self.row_size;
|
||||
let mut x: i32 = (bits_offset % self.row_size) * 32;
|
||||
let the_bits: i32 = self.bits[bits_offset];
|
||||
let mut bit: i32 = 0;
|
||||
while (the_bits << (31 - bit)) == 0 {
|
||||
bit += 1;
|
||||
}
|
||||
x += bit;
|
||||
return : vec![i32; 2] = vec![x, y, ]
|
||||
;
|
||||
}
|
||||
|
||||
pub fn get_bottom_right_on_bit(&self) -> Vec<i32> {
|
||||
let bits_offset: i32 = self.bits.len() - 1;
|
||||
while bits_offset >= 0 && self.bits[bits_offset] == 0 {
|
||||
bits_offset -= 1;
|
||||
}
|
||||
if bits_offset < 0 {
|
||||
return null;
|
||||
}
|
||||
let y: i32 = bits_offset / self.row_size;
|
||||
let mut x: i32 = (bits_offset % self.row_size) * 32;
|
||||
let the_bits: i32 = self.bits[bits_offset];
|
||||
let mut bit: i32 = 31;
|
||||
while (the_bits >> /* >>> */ bit) == 0 {
|
||||
bit -= 1;
|
||||
}
|
||||
x += bit;
|
||||
return : vec![i32; 2] = vec![x, y, ]
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The width of the matrix
|
||||
*/
|
||||
pub fn get_width(&self) -> i32 {
|
||||
return self.width;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The height of the matrix
|
||||
*/
|
||||
pub fn get_height(&self) -> i32 {
|
||||
return self.height;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The row size of the matrix
|
||||
*/
|
||||
pub fn get_row_size(&self) -> i32 {
|
||||
return self.row_size;
|
||||
}
|
||||
|
||||
pub fn equals(&self, o: &Object) -> bool {
|
||||
if !(o instanceof BitMatrix) {
|
||||
return false;
|
||||
}
|
||||
let other: BitMatrix = o as BitMatrix;
|
||||
return self.width == other.width && self.height == other.height && self.row_size == other.rowSize && Arrays::equals(&self.bits, other.bits);
|
||||
}
|
||||
|
||||
pub fn hash_code(&self) -> i32 {
|
||||
let mut hash: i32 = self.width;
|
||||
hash = 31 * hash + self.width;
|
||||
hash = 31 * hash + self.height;
|
||||
hash = 31 * hash + self.row_size;
|
||||
hash = 31 * hash + Arrays::hash_code(&self.bits);
|
||||
return hash;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string representation using "X" for set and " " for unset bits
|
||||
*/
|
||||
pub fn to_string(&self) -> String {
|
||||
return self.to_string("X ", " ");
|
||||
}
|
||||
|
||||
/**
|
||||
* @param setString representation of a set bit
|
||||
* @param unsetString representation of an unset bit
|
||||
* @return string representation of entire matrix utilizing given strings
|
||||
*/
|
||||
pub fn to_string(&self, set_string: &String, unset_string: &String) -> String {
|
||||
return self.build_to_string(&set_string, &unset_string, "\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* @param setString representation of a set bit
|
||||
* @param unsetString representation of an unset bit
|
||||
* @param lineSeparator newline character in string representation
|
||||
* @return string representation of entire matrix utilizing given strings and line separator
|
||||
* @deprecated call {@link #toString(String,String)} only, which uses \n line separator always
|
||||
*/
|
||||
pub fn to_string(&self, set_string: &String, unset_string: &String, line_separator: &String) -> String {
|
||||
return self.build_to_string(&set_string, &unset_string, &line_separator);
|
||||
}
|
||||
|
||||
fn build_to_string(&self, set_string: &String, unset_string: &String, line_separator: &String) -> String {
|
||||
let result: StringBuilder = StringBuilder::new(self.height * (self.width + 1));
|
||||
{
|
||||
let mut y: i32 = 0;
|
||||
while y < self.height {
|
||||
{
|
||||
{
|
||||
let mut x: i32 = 0;
|
||||
while x < self.width {
|
||||
{
|
||||
result.append( if self.get(x, y) { set_string } else { unset_string });
|
||||
}
|
||||
x += 1;
|
||||
}
|
||||
}
|
||||
|
||||
result.append(&line_separator);
|
||||
}
|
||||
y += 1;
|
||||
}
|
||||
}
|
||||
|
||||
return result.to_string();
|
||||
}
|
||||
|
||||
pub fn clone(&self) -> BitMatrix {
|
||||
return BitMatrix::new(self.width, self.height, self.row_size, &self.bits.clone());
|
||||
}
|
||||
}
|
||||
|
||||
110
port_src/output/zxing/common/bit_source.rs
Normal file
110
port_src/output/zxing/common/bit_source.rs
Normal file
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* 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::common;
|
||||
|
||||
/**
|
||||
* <p>This provides an easy abstraction to read bits at a time from a sequence of bytes, where the
|
||||
* number of bits read is not often a multiple of 8.</p>
|
||||
*
|
||||
* <p>This class is thread-safe but not reentrant -- unless the caller modifies the bytes array
|
||||
* it passed in, in which case all bets are off.</p>
|
||||
*
|
||||
* @author Sean Owen
|
||||
*/
|
||||
pub struct BitSource {
|
||||
|
||||
let bytes: Vec<i8>;
|
||||
|
||||
let byte_offset: i32;
|
||||
|
||||
let bit_offset: i32;
|
||||
}
|
||||
|
||||
impl BitSource {
|
||||
|
||||
/**
|
||||
* @param bytes bytes from which this will read bits. Bits will be read from the first byte first.
|
||||
* Bits are read within a byte from most-significant to least-significant bit.
|
||||
*/
|
||||
pub fn new( bytes: &Vec<i8>) -> BitSource {
|
||||
let .bytes = bytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return index of next bit in current byte which would be read by the next call to {@link #readBits(int)}.
|
||||
*/
|
||||
pub fn get_bit_offset(&self) -> i32 {
|
||||
return self.bit_offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return index of next byte in input byte array which would be read by the next call to {@link #readBits(int)}.
|
||||
*/
|
||||
pub fn get_byte_offset(&self) -> i32 {
|
||||
return self.byte_offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param numBits number of bits to read
|
||||
* @return int representing the bits read. The bits will appear as the least-significant
|
||||
* bits of the int
|
||||
* @throws IllegalArgumentException if numBits isn't in [1,32] or more than is available
|
||||
*/
|
||||
pub fn read_bits(&self, num_bits: i32) -> i32 {
|
||||
if num_bits < 1 || num_bits > 32 || num_bits > self.available() {
|
||||
throw IllegalArgumentException::new(&String::value_of(num_bits));
|
||||
}
|
||||
let mut result: i32 = 0;
|
||||
// First, read remainder from current byte
|
||||
if self.bit_offset > 0 {
|
||||
let bits_left: i32 = 8 - self.bit_offset;
|
||||
let to_read: i32 = Math::min(num_bits, bits_left);
|
||||
let bits_to_not_read: i32 = bits_left - to_read;
|
||||
let mask: i32 = (0xFF >> (8 - to_read)) << bits_to_not_read;
|
||||
result = (self.bytes[self.byte_offset] & mask) >> bits_to_not_read;
|
||||
num_bits -= to_read;
|
||||
self.bit_offset += to_read;
|
||||
if self.bit_offset == 8 {
|
||||
self.bit_offset = 0;
|
||||
self.byte_offset += 1;
|
||||
}
|
||||
}
|
||||
// Next read whole bytes
|
||||
if num_bits > 0 {
|
||||
while num_bits >= 8 {
|
||||
result = (result << 8) | (self.bytes[self.byte_offset] & 0xFF);
|
||||
self.byte_offset += 1;
|
||||
num_bits -= 8;
|
||||
}
|
||||
// Finally read a partial byte
|
||||
if num_bits > 0 {
|
||||
let bits_to_not_read: i32 = 8 - num_bits;
|
||||
let mask: i32 = (0xFF >> bits_to_not_read) << bits_to_not_read;
|
||||
result = (result << num_bits) | ((self.bytes[self.byte_offset] & mask) >> bits_to_not_read);
|
||||
self.bit_offset += num_bits;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return number of bits that can be read successfully
|
||||
*/
|
||||
pub fn available(&self) -> i32 {
|
||||
return 8 * (self.bytes.len() - self.byte_offset) - self.bit_offset;
|
||||
}
|
||||
}
|
||||
|
||||
110
port_src/output/zxing/common/character_set_e_c_i.rs
Normal file
110
port_src/output/zxing/common/character_set_e_c_i.rs
Normal file
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* 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::common;
|
||||
|
||||
/**
|
||||
* Encapsulates a Character Set ECI, according to "Extended Channel Interpretations" 5.3.1.1
|
||||
* of ISO 18004.
|
||||
*
|
||||
* @author Sean Owen
|
||||
*/
|
||||
pub enum CharacterSetECI {
|
||||
|
||||
// Enum name is a Java encoding valid for java.lang and java.io
|
||||
Cp437( : vec![i32; 2] = vec![0, 2, ]
|
||||
), ISO8859_1( : vec![i32; 2] = vec![1, 3, ]
|
||||
, "ISO-8859-1"), ISO8859_2(4, "ISO-8859-2"), ISO8859_3(5, "ISO-8859-3"), ISO8859_4(6, "ISO-8859-4"), ISO8859_5(7, "ISO-8859-5"), // ISO8859_6(8, "ISO-8859-6"),
|
||||
ISO8859_7(9, "ISO-8859-7"), // ISO8859_8(10, "ISO-8859-8"),
|
||||
ISO8859_9(11, "ISO-8859-9"), // ISO8859_11(13, "ISO-8859-11"),
|
||||
ISO8859_13(15, "ISO-8859-13"), // ISO8859_14(16, "ISO-8859-14"),
|
||||
ISO8859_15(17, "ISO-8859-15"), ISO8859_16(18, "ISO-8859-16"), SJIS(20, "Shift_JIS"), Cp1250(21, "windows-1250"), Cp1251(22, "windows-1251"), Cp1252(23, "windows-1252"), Cp1256(24, "windows-1256"), UnicodeBigUnmarked(25, "UTF-16BE", "UnicodeBig"), UTF8(26, "UTF-8"), ASCII( : vec![i32; 2] = vec![27, 170, ]
|
||||
, "US-ASCII"), Big5(28), GB18030(29, "GB2312", "EUC_CN", "GBK"), EUC_KR(30, "EUC-KR");
|
||||
|
||||
const VALUE_TO_ECI: Map<Integer, CharacterSetECI> = HashMap<>::new();
|
||||
|
||||
const NAME_TO_ECI: Map<String, CharacterSetECI> = HashMap<>::new();
|
||||
|
||||
static {
|
||||
for let eci: CharacterSetECI in self.values() {
|
||||
for let value: i32 in eci.values {
|
||||
VALUE_TO_ECI::put(value, eci);
|
||||
}
|
||||
NAME_TO_ECI::put(&eci.name(), eci);
|
||||
for let name: String in eci.otherEncodingNames {
|
||||
NAME_TO_ECI::put(&name, eci);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut values: Vec<i32>;
|
||||
|
||||
let other_encoding_names: Vec<String>;
|
||||
|
||||
fn new( value: i32) -> CharacterSetECI {
|
||||
this( : vec![i32; 1] = vec![value, ]
|
||||
);
|
||||
}
|
||||
|
||||
fn new( value: i32, other_encoding_names: &String) -> CharacterSetECI {
|
||||
let .values = : vec![i32; 1] = vec![value, ]
|
||||
;
|
||||
let .otherEncodingNames = other_encoding_names;
|
||||
}
|
||||
|
||||
fn new( values: &Vec<i32>, other_encoding_names: &String) -> CharacterSetECI {
|
||||
let .values = values;
|
||||
let .otherEncodingNames = other_encoding_names;
|
||||
}
|
||||
|
||||
pub fn get_value(&self) -> i32 {
|
||||
return self.values[0];
|
||||
}
|
||||
|
||||
pub fn get_charset(&self) -> Charset {
|
||||
return Charset::for_name(&name());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param charset Java character set object
|
||||
* @return CharacterSetECI representing ECI for character encoding, or null if it is legal
|
||||
* but unsupported
|
||||
*/
|
||||
pub fn get_character_set_e_c_i( charset: &Charset) -> CharacterSetECI {
|
||||
return NAME_TO_ECI::get(&charset.name());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param value character set ECI value
|
||||
* @return {@code CharacterSetECI} representing ECI of given value, or null if it is legal but
|
||||
* unsupported
|
||||
* @throws FormatException if ECI value is invalid
|
||||
*/
|
||||
pub fn get_character_set_e_c_i_by_value( value: i32) -> /* throws FormatException */Result<CharacterSetECI, Rc<Exception>> {
|
||||
if value < 0 || value >= 900 {
|
||||
throw FormatException::get_format_instance();
|
||||
}
|
||||
return Ok(VALUE_TO_ECI::get(value));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param name character set ECI encoding name
|
||||
* @return CharacterSetECI representing ECI for character encoding, or null if it is legal
|
||||
* but unsupported
|
||||
*/
|
||||
pub fn get_character_set_e_c_i_by_name( name: &String) -> CharacterSetECI {
|
||||
return NAME_TO_ECI::get(&name);
|
||||
}
|
||||
}
|
||||
168
port_src/output/zxing/common/decoder_result.rs
Normal file
168
port_src/output/zxing/common/decoder_result.rs
Normal file
@@ -0,0 +1,168 @@
|
||||
/*
|
||||
* 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::common;
|
||||
|
||||
/**
|
||||
* <p>Encapsulates the result of decoding a matrix of bits. This typically
|
||||
* applies to 2D barcode formats. For now it contains the raw bytes obtained,
|
||||
* as well as a String interpretation of those bytes, if applicable.</p>
|
||||
*
|
||||
* @author Sean Owen
|
||||
*/
|
||||
pub struct DecoderResult {
|
||||
|
||||
let raw_bytes: Vec<i8>;
|
||||
|
||||
let num_bits: i32;
|
||||
|
||||
let text: String;
|
||||
|
||||
let byte_segments: List<Vec<i8>>;
|
||||
|
||||
let ec_level: String;
|
||||
|
||||
let errors_corrected: Integer;
|
||||
|
||||
let erasures: Integer;
|
||||
|
||||
let other: Object;
|
||||
|
||||
let structured_append_parity: i32;
|
||||
|
||||
let structured_append_sequence_number: i32;
|
||||
|
||||
let symbology_modifier: i32;
|
||||
}
|
||||
|
||||
impl DecoderResult {
|
||||
|
||||
pub fn new( raw_bytes: &Vec<i8>, text: &String, byte_segments: &List<Vec<i8>>, ec_level: &String) -> DecoderResult {
|
||||
this(&raw_bytes, &text, &byte_segments, &ec_level, -1, -1, 0);
|
||||
}
|
||||
|
||||
pub fn new( raw_bytes: &Vec<i8>, text: &String, byte_segments: &List<Vec<i8>>, ec_level: &String, symbology_modifier: i32) -> DecoderResult {
|
||||
this(&raw_bytes, &text, &byte_segments, &ec_level, -1, -1, symbology_modifier);
|
||||
}
|
||||
|
||||
pub fn new( raw_bytes: &Vec<i8>, text: &String, byte_segments: &List<Vec<i8>>, ec_level: &String, sa_sequence: i32, sa_parity: i32) -> DecoderResult {
|
||||
this(&raw_bytes, &text, &byte_segments, &ec_level, sa_sequence, sa_parity, 0);
|
||||
}
|
||||
|
||||
pub fn new( raw_bytes: &Vec<i8>, text: &String, byte_segments: &List<Vec<i8>>, ec_level: &String, sa_sequence: i32, sa_parity: i32, symbology_modifier: i32) -> DecoderResult {
|
||||
let .rawBytes = raw_bytes;
|
||||
let .numBits = if raw_bytes == null { 0 } else { 8 * raw_bytes.len() };
|
||||
let .text = text;
|
||||
let .byteSegments = byte_segments;
|
||||
let .ecLevel = ec_level;
|
||||
let .structuredAppendParity = sa_parity;
|
||||
let .structuredAppendSequenceNumber = sa_sequence;
|
||||
let .symbologyModifier = symbology_modifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return raw bytes representing the result, or {@code null} if not applicable
|
||||
*/
|
||||
pub fn get_raw_bytes(&self) -> Vec<i8> {
|
||||
return self.raw_bytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return how many bits of {@link #getRawBytes()} are valid; typically 8 times its length
|
||||
* @since 3.3.0
|
||||
*/
|
||||
pub fn get_num_bits(&self) -> i32 {
|
||||
return self.num_bits;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param numBits overrides the number of bits that are valid in {@link #getRawBytes()}
|
||||
* @since 3.3.0
|
||||
*/
|
||||
pub fn set_num_bits(&self, num_bits: i32) {
|
||||
self.numBits = num_bits;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return text representation of the result
|
||||
*/
|
||||
pub fn get_text(&self) -> String {
|
||||
return self.text;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return list of byte segments in the result, or {@code null} if not applicable
|
||||
*/
|
||||
pub fn get_byte_segments(&self) -> List<Vec<i8>> {
|
||||
return self.byte_segments;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return name of error correction level used, or {@code null} if not applicable
|
||||
*/
|
||||
pub fn get_e_c_level(&self) -> String {
|
||||
return self.ec_level;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return number of errors corrected, or {@code null} if not applicable
|
||||
*/
|
||||
pub fn get_errors_corrected(&self) -> Integer {
|
||||
return self.errors_corrected;
|
||||
}
|
||||
|
||||
pub fn set_errors_corrected(&self, errors_corrected: &Integer) {
|
||||
self.errorsCorrected = errors_corrected;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return number of erasures corrected, or {@code null} if not applicable
|
||||
*/
|
||||
pub fn get_erasures(&self) -> Integer {
|
||||
return self.erasures;
|
||||
}
|
||||
|
||||
pub fn set_erasures(&self, erasures: &Integer) {
|
||||
self.erasures = erasures;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return arbitrary additional metadata
|
||||
*/
|
||||
pub fn get_other(&self) -> Object {
|
||||
return self.other;
|
||||
}
|
||||
|
||||
pub fn set_other(&self, other: &Object) {
|
||||
self.other = other;
|
||||
}
|
||||
|
||||
pub fn has_structured_append(&self) -> bool {
|
||||
return self.structured_append_parity >= 0 && self.structured_append_sequence_number >= 0;
|
||||
}
|
||||
|
||||
pub fn get_structured_append_parity(&self) -> i32 {
|
||||
return self.structured_append_parity;
|
||||
}
|
||||
|
||||
pub fn get_structured_append_sequence_number(&self) -> i32 {
|
||||
return self.structured_append_sequence_number;
|
||||
}
|
||||
|
||||
pub fn get_symbology_modifier(&self) -> i32 {
|
||||
return self.symbology_modifier;
|
||||
}
|
||||
}
|
||||
|
||||
92
port_src/output/zxing/common/default_grid_sampler.rs
Normal file
92
port_src/output/zxing/common/default_grid_sampler.rs
Normal file
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* 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::common;
|
||||
|
||||
/**
|
||||
* @author Sean Owen
|
||||
*/
|
||||
pub struct DefaultGridSampler {
|
||||
super: GridSampler;
|
||||
}
|
||||
|
||||
impl DefaultGridSampler {
|
||||
|
||||
pub fn sample_grid(&self, image: &BitMatrix, dimension_x: i32, dimension_y: i32, p1_to_x: f32, p1_to_y: f32, p2_to_x: f32, p2_to_y: f32, p3_to_x: f32, p3_to_y: f32, p4_to_x: f32, p4_to_y: f32, p1_from_x: f32, p1_from_y: f32, p2_from_x: f32, p2_from_y: f32, p3_from_x: f32, p3_from_y: f32, p4_from_x: f32, p4_from_y: f32) -> /* throws NotFoundException */Result<BitMatrix, Rc<Exception>> {
|
||||
let transform: PerspectiveTransform = PerspectiveTransform::quadrilateral_to_quadrilateral(p1_to_x, p1_to_y, p2_to_x, p2_to_y, p3_to_x, p3_to_y, p4_to_x, p4_to_y, p1_from_x, p1_from_y, p2_from_x, p2_from_y, p3_from_x, p3_from_y, p4_from_x, p4_from_y);
|
||||
return Ok(self.sample_grid(image, dimension_x, dimension_y, transform));
|
||||
}
|
||||
|
||||
pub fn sample_grid(&self, image: &BitMatrix, dimension_x: i32, dimension_y: i32, transform: &PerspectiveTransform) -> /* throws NotFoundException */Result<BitMatrix, Rc<Exception>> {
|
||||
if dimension_x <= 0 || dimension_y <= 0 {
|
||||
throw NotFoundException::get_not_found_instance();
|
||||
}
|
||||
let bits: BitMatrix = BitMatrix::new(dimension_x, dimension_y);
|
||||
let mut points: [f32; 2.0 * dimension_x] = [0.0; 2.0 * dimension_x];
|
||||
{
|
||||
let mut y: i32 = 0;
|
||||
while y < dimension_y {
|
||||
{
|
||||
let max: i32 = points.len();
|
||||
let i_value: f32 = y + 0.5f;
|
||||
{
|
||||
let mut x: i32 = 0;
|
||||
while x < max {
|
||||
{
|
||||
points[x] = (x / 2.0) as f32 + 0.5f;
|
||||
points[x + 1] = i_value;
|
||||
}
|
||||
x += 2;
|
||||
}
|
||||
}
|
||||
|
||||
transform.transform_points(&points);
|
||||
// Quick check to see if points transformed to something inside the image;
|
||||
// sufficient to check the endpoints
|
||||
check_and_nudge_points(image, &points);
|
||||
let tryResult1 = 0;
|
||||
'try1: loop {
|
||||
{
|
||||
{
|
||||
let mut x: i32 = 0;
|
||||
while x < max {
|
||||
{
|
||||
if image.get(points[x] as i32, points[x + 1] as i32) {
|
||||
// Black(-ish) pixel
|
||||
bits.set(x / 2, y);
|
||||
}
|
||||
}
|
||||
x += 2;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
break 'try1
|
||||
}
|
||||
match tryResult1 {
|
||||
catch ( aioobe: &ArrayIndexOutOfBoundsException) {
|
||||
throw NotFoundException::get_not_found_instance();
|
||||
} 0 => break
|
||||
}
|
||||
|
||||
}
|
||||
y += 1;
|
||||
}
|
||||
}
|
||||
|
||||
return Ok(bits);
|
||||
}
|
||||
}
|
||||
|
||||
80
port_src/output/zxing/common/detector/math_utils.rs
Normal file
80
port_src/output/zxing/common/detector/math_utils.rs
Normal file
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* 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::common::detector;
|
||||
|
||||
/**
|
||||
* General math-related and numeric utility functions.
|
||||
*/
|
||||
pub struct MathUtils {
|
||||
}
|
||||
|
||||
impl MathUtils {
|
||||
|
||||
fn new() -> MathUtils {
|
||||
}
|
||||
|
||||
/**
|
||||
* Ends up being a bit faster than {@link Math#round(float)}. This merely rounds its
|
||||
* argument to the nearest int, where x.5 rounds up to x+1. Semantics of this shortcut
|
||||
* differ slightly from {@link Math#round(float)} in that half rounds down for negative
|
||||
* values. -2.5 rounds to -3, not -2. For purposes here it makes no difference.
|
||||
*
|
||||
* @param d real value to round
|
||||
* @return nearest {@code int}
|
||||
*/
|
||||
pub fn round( d: f32) -> i32 {
|
||||
return (d + ( if d < 0.0f { -0.5f } else { 0.5f })) as i32;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param aX point A x coordinate
|
||||
* @param aY point A y coordinate
|
||||
* @param bX point B x coordinate
|
||||
* @param bY point B y coordinate
|
||||
* @return Euclidean distance between points A and B
|
||||
*/
|
||||
pub fn distance( a_x: f32, a_y: f32, b_x: f32, b_y: f32) -> f32 {
|
||||
let x_diff: f64 = a_x - b_x;
|
||||
let y_diff: f64 = a_y - b_y;
|
||||
return Math::sqrt(x_diff * x_diff + y_diff * y_diff) as f32;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param aX point A x coordinate
|
||||
* @param aY point A y coordinate
|
||||
* @param bX point B x coordinate
|
||||
* @param bY point B y coordinate
|
||||
* @return Euclidean distance between points A and B
|
||||
*/
|
||||
pub fn distance( a_x: i32, a_y: i32, b_x: i32, b_y: i32) -> f32 {
|
||||
let x_diff: f64 = a_x - b_x;
|
||||
let y_diff: f64 = a_y - b_y;
|
||||
return Math::sqrt(x_diff * x_diff + y_diff * y_diff) as f32;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array values to sum
|
||||
* @return sum of values in array
|
||||
*/
|
||||
pub fn sum( array: &Vec<i32>) -> i32 {
|
||||
let mut count: i32 = 0;
|
||||
for let a: i32 in array {
|
||||
count += a;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,200 @@
|
||||
/*
|
||||
* 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::common::detector;
|
||||
|
||||
/**
|
||||
* <p>A somewhat generic detector that looks for a barcode-like rectangular region within an image.
|
||||
* It looks within a mostly white region of an image for a region of black and white, but mostly
|
||||
* black. It returns the four corners of the region, as best it can determine.</p>
|
||||
*
|
||||
* @author Sean Owen
|
||||
* @deprecated without replacement since 3.3.0
|
||||
*/
|
||||
|
||||
const MAX_MODULES: i32 = 32;
|
||||
pub struct MonochromeRectangleDetector {
|
||||
|
||||
let image: BitMatrix;
|
||||
}
|
||||
|
||||
impl MonochromeRectangleDetector {
|
||||
|
||||
pub fn new( image: &BitMatrix) -> MonochromeRectangleDetector {
|
||||
let .image = image;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Detects a rectangular region of black and white -- mostly black -- with a region of mostly
|
||||
* white, in an image.</p>
|
||||
*
|
||||
* @return {@link ResultPoint}[] describing the corners of the rectangular region. The first and
|
||||
* last points are opposed on the diagonal, as are the second and third. The first point will be
|
||||
* the topmost point and the last, the bottommost. The second point will be leftmost and the
|
||||
* third, the rightmost
|
||||
* @throws NotFoundException if no Data Matrix Code can be found
|
||||
*/
|
||||
pub fn detect(&self) -> /* throws NotFoundException */Result<Vec<ResultPoint>, Rc<Exception>> {
|
||||
let height: i32 = self.image.get_height();
|
||||
let width: i32 = self.image.get_width();
|
||||
let half_height: i32 = height / 2;
|
||||
let half_width: i32 = width / 2;
|
||||
let delta_y: i32 = Math::max(1, height / (MAX_MODULES * 8));
|
||||
let delta_x: i32 = Math::max(1, width / (MAX_MODULES * 8));
|
||||
let mut top: i32 = 0;
|
||||
let mut bottom: i32 = height;
|
||||
let mut left: i32 = 0;
|
||||
let mut right: i32 = width;
|
||||
let point_a: ResultPoint = self.find_corner_from_center(half_width, 0, left, right, half_height, -delta_y, top, bottom, half_width / 2);
|
||||
top = point_a.get_y() as i32 - 1;
|
||||
let point_b: ResultPoint = self.find_corner_from_center(half_width, -delta_x, left, right, half_height, 0, top, bottom, half_height / 2);
|
||||
left = point_b.get_x() as i32 - 1;
|
||||
let point_c: ResultPoint = self.find_corner_from_center(half_width, delta_x, left, right, half_height, 0, top, bottom, half_height / 2);
|
||||
right = point_c.get_x() as i32 + 1;
|
||||
let point_d: ResultPoint = self.find_corner_from_center(half_width, 0, left, right, half_height, delta_y, top, bottom, half_width / 2);
|
||||
bottom = point_d.get_y() as i32 + 1;
|
||||
// Go try to find point A again with better information -- might have been off at first.
|
||||
point_a = self.find_corner_from_center(half_width, 0, left, right, half_height, -delta_y, top, bottom, half_width / 4);
|
||||
return Ok( : vec![ResultPoint; 4] = vec![point_a, point_b, point_c, point_d, ]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to locate a corner of the barcode by scanning up, down, left or right from a center
|
||||
* point which should be within the barcode.
|
||||
*
|
||||
* @param centerX center's x component (horizontal)
|
||||
* @param deltaX same as deltaY but change in x per step instead
|
||||
* @param left minimum value of x
|
||||
* @param right maximum value of x
|
||||
* @param centerY center's y component (vertical)
|
||||
* @param deltaY change in y per step. If scanning up this is negative; down, positive;
|
||||
* left or right, 0
|
||||
* @param top minimum value of y to search through (meaningless when di == 0)
|
||||
* @param bottom maximum value of y
|
||||
* @param maxWhiteRun maximum run of white pixels that can still be considered to be within
|
||||
* the barcode
|
||||
* @return a {@link ResultPoint} encapsulating the corner that was found
|
||||
* @throws NotFoundException if such a point cannot be found
|
||||
*/
|
||||
fn find_corner_from_center(&self, center_x: i32, delta_x: i32, left: i32, right: i32, center_y: i32, delta_y: i32, top: i32, bottom: i32, max_white_run: i32) -> /* throws NotFoundException */Result<ResultPoint, Rc<Exception>> {
|
||||
let last_range: Vec<i32> = null;
|
||||
{
|
||||
let mut y: i32 = center_y, let mut x: i32 = center_x;
|
||||
while y < bottom && y >= top && x < right && x >= left {
|
||||
{
|
||||
let mut range: Vec<i32>;
|
||||
if delta_x == 0 {
|
||||
// horizontal slices, up and down
|
||||
range = self.black_white_range(y, max_white_run, left, right, true);
|
||||
} else {
|
||||
// vertical slices, left and right
|
||||
range = self.black_white_range(x, max_white_run, top, bottom, false);
|
||||
}
|
||||
if range == null {
|
||||
if last_range == null {
|
||||
throw NotFoundException::get_not_found_instance();
|
||||
}
|
||||
// lastRange was found
|
||||
if delta_x == 0 {
|
||||
let last_y: i32 = y - delta_y;
|
||||
if last_range[0] < center_x {
|
||||
if last_range[1] > center_x {
|
||||
// straddle, choose one or the other based on direction
|
||||
return Ok(ResultPoint::new(last_range[ if delta_y > 0 { 0 } else { 1 }], last_y));
|
||||
}
|
||||
return Ok(ResultPoint::new(last_range[0], last_y));
|
||||
} else {
|
||||
return Ok(ResultPoint::new(last_range[1], last_y));
|
||||
}
|
||||
} else {
|
||||
let last_x: i32 = x - delta_x;
|
||||
if last_range[0] < center_y {
|
||||
if last_range[1] > center_y {
|
||||
return Ok(ResultPoint::new(last_x, last_range[ if delta_x < 0 { 0 } else { 1 }]));
|
||||
}
|
||||
return Ok(ResultPoint::new(last_x, last_range[0]));
|
||||
} else {
|
||||
return Ok(ResultPoint::new(last_x, last_range[1]));
|
||||
}
|
||||
}
|
||||
}
|
||||
last_range = range;
|
||||
}
|
||||
y += delta_y;
|
||||
x += delta_x;
|
||||
}
|
||||
}
|
||||
|
||||
throw NotFoundException::get_not_found_instance();
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the start and end of a region of pixels, either horizontally or vertically, that could
|
||||
* be part of a Data Matrix barcode.
|
||||
*
|
||||
* @param fixedDimension if scanning horizontally, this is the row (the fixed vertical location)
|
||||
* where we are scanning. If scanning vertically it's the column, the fixed horizontal location
|
||||
* @param maxWhiteRun largest run of white pixels that can still be considered part of the
|
||||
* barcode region
|
||||
* @param minDim minimum pixel location, horizontally or vertically, to consider
|
||||
* @param maxDim maximum pixel location, horizontally or vertically, to consider
|
||||
* @param horizontal if true, we're scanning left-right, instead of up-down
|
||||
* @return int[] with start and end of found range, or null if no such range is found
|
||||
* (e.g. only white was found)
|
||||
*/
|
||||
fn black_white_range(&self, fixed_dimension: i32, max_white_run: i32, min_dim: i32, max_dim: i32, horizontal: bool) -> Vec<i32> {
|
||||
let center: i32 = (min_dim + max_dim) / 2;
|
||||
// Scan left/up first
|
||||
let mut start: i32 = center;
|
||||
while start >= min_dim {
|
||||
if if horizontal { self.image.get(start, fixed_dimension) } else { self.image.get(fixed_dimension, start) } {
|
||||
start -= 1;
|
||||
} else {
|
||||
let white_run_start: i32 = start;
|
||||
loop { {
|
||||
start -= 1;
|
||||
}if !(start >= min_dim && !( if horizontal { self.image.get(start, fixed_dimension) } else { self.image.get(fixed_dimension, start) })) break;}
|
||||
let white_run_size: i32 = white_run_start - start;
|
||||
if start < min_dim || white_run_size > max_white_run {
|
||||
start = white_run_start;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
start += 1;
|
||||
// Then try right/down
|
||||
let mut end: i32 = center;
|
||||
while end < max_dim {
|
||||
if if horizontal { self.image.get(end, fixed_dimension) } else { self.image.get(fixed_dimension, end) } {
|
||||
end += 1;
|
||||
} else {
|
||||
let white_run_start: i32 = end;
|
||||
loop { {
|
||||
end += 1;
|
||||
}if !(end < max_dim && !( if horizontal { self.image.get(end, fixed_dimension) } else { self.image.get(fixed_dimension, end) })) break;}
|
||||
let white_run_size: i32 = end - white_run_start;
|
||||
if end >= max_dim || white_run_size > max_white_run {
|
||||
end = white_run_start;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
end -= 1;
|
||||
return if end > start { : vec![i32; 2] = vec![start, end, ]
|
||||
} else { null };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,341 @@
|
||||
/*
|
||||
* 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::common::detector;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Detects a candidate barcode-like rectangular region within an image. It
|
||||
* starts around the center of the image, increases the size of the candidate
|
||||
* region until it finds a white rectangular region. By keeping track of the
|
||||
* last black points it encountered, it determines the corners of the barcode.
|
||||
* </p>
|
||||
*
|
||||
* @author David Olivier
|
||||
*/
|
||||
|
||||
const INIT_SIZE: i32 = 10;
|
||||
|
||||
const CORR: i32 = 1;
|
||||
pub struct WhiteRectangleDetector {
|
||||
|
||||
let image: BitMatrix;
|
||||
|
||||
let mut height: i32;
|
||||
|
||||
let mut width: i32;
|
||||
|
||||
let left_init: i32;
|
||||
|
||||
let right_init: i32;
|
||||
|
||||
let down_init: i32;
|
||||
|
||||
let up_init: i32;
|
||||
}
|
||||
|
||||
impl WhiteRectangleDetector {
|
||||
|
||||
pub fn new( image: &BitMatrix) -> WhiteRectangleDetector throws NotFoundException {
|
||||
this(image, INIT_SIZE, image.get_width() / 2, image.get_height() / 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param image barcode image to find a rectangle in
|
||||
* @param initSize initial size of search area around center
|
||||
* @param x x position of search center
|
||||
* @param y y position of search center
|
||||
* @throws NotFoundException if image is too small to accommodate {@code initSize}
|
||||
*/
|
||||
pub fn new( image: &BitMatrix, init_size: i32, x: i32, y: i32) -> WhiteRectangleDetector throws NotFoundException {
|
||||
let .image = image;
|
||||
height = image.get_height();
|
||||
width = image.get_width();
|
||||
let halfsize: i32 = init_size / 2;
|
||||
left_init = x - halfsize;
|
||||
right_init = x + halfsize;
|
||||
up_init = y - halfsize;
|
||||
down_init = y + halfsize;
|
||||
if up_init < 0 || left_init < 0 || down_init >= height || right_init >= width {
|
||||
throw NotFoundException::get_not_found_instance();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Detects a candidate barcode-like rectangular region within an image. It
|
||||
* starts around the center of the image, increases the size of the candidate
|
||||
* region until it finds a white rectangular region.
|
||||
* </p>
|
||||
*
|
||||
* @return {@link ResultPoint}[] describing the corners of the rectangular
|
||||
* region. The first and last points are opposed on the diagonal, as
|
||||
* are the second and third. The first point will be the topmost
|
||||
* point and the last, the bottommost. The second point will be
|
||||
* leftmost and the third, the rightmost
|
||||
* @throws NotFoundException if no Data Matrix Code can be found
|
||||
*/
|
||||
pub fn detect(&self) -> /* throws NotFoundException */Result<Vec<ResultPoint>, Rc<Exception>> {
|
||||
let mut left: i32 = self.left_init;
|
||||
let mut right: i32 = self.right_init;
|
||||
let mut up: i32 = self.up_init;
|
||||
let mut down: i32 = self.down_init;
|
||||
let size_exceeded: bool = false;
|
||||
let a_black_point_found_on_border: bool = true;
|
||||
let at_least_one_black_point_found_on_right: bool = false;
|
||||
let at_least_one_black_point_found_on_bottom: bool = false;
|
||||
let at_least_one_black_point_found_on_left: bool = false;
|
||||
let at_least_one_black_point_found_on_top: bool = false;
|
||||
while a_black_point_found_on_border {
|
||||
a_black_point_found_on_border = false;
|
||||
// .....
|
||||
// . |
|
||||
// .....
|
||||
let right_border_not_white: bool = true;
|
||||
while (right_border_not_white || !at_least_one_black_point_found_on_right) && right < self.width {
|
||||
right_border_not_white = self.contains_black_point(up, down, right, false);
|
||||
if right_border_not_white {
|
||||
right += 1;
|
||||
a_black_point_found_on_border = true;
|
||||
at_least_one_black_point_found_on_right = true;
|
||||
} else if !at_least_one_black_point_found_on_right {
|
||||
right += 1;
|
||||
}
|
||||
}
|
||||
if right >= self.width {
|
||||
size_exceeded = true;
|
||||
break;
|
||||
}
|
||||
// .....
|
||||
// . .
|
||||
// .___.
|
||||
let bottom_border_not_white: bool = true;
|
||||
while (bottom_border_not_white || !at_least_one_black_point_found_on_bottom) && down < self.height {
|
||||
bottom_border_not_white = self.contains_black_point(left, right, down, true);
|
||||
if bottom_border_not_white {
|
||||
down += 1;
|
||||
a_black_point_found_on_border = true;
|
||||
at_least_one_black_point_found_on_bottom = true;
|
||||
} else if !at_least_one_black_point_found_on_bottom {
|
||||
down += 1;
|
||||
}
|
||||
}
|
||||
if down >= self.height {
|
||||
size_exceeded = true;
|
||||
break;
|
||||
}
|
||||
// .....
|
||||
// | .
|
||||
// .....
|
||||
let left_border_not_white: bool = true;
|
||||
while (left_border_not_white || !at_least_one_black_point_found_on_left) && left >= 0 {
|
||||
left_border_not_white = self.contains_black_point(up, down, left, false);
|
||||
if left_border_not_white {
|
||||
left -= 1;
|
||||
a_black_point_found_on_border = true;
|
||||
at_least_one_black_point_found_on_left = true;
|
||||
} else if !at_least_one_black_point_found_on_left {
|
||||
left -= 1;
|
||||
}
|
||||
}
|
||||
if left < 0 {
|
||||
size_exceeded = true;
|
||||
break;
|
||||
}
|
||||
// .___.
|
||||
// . .
|
||||
// .....
|
||||
let top_border_not_white: bool = true;
|
||||
while (top_border_not_white || !at_least_one_black_point_found_on_top) && up >= 0 {
|
||||
top_border_not_white = self.contains_black_point(left, right, up, true);
|
||||
if top_border_not_white {
|
||||
up -= 1;
|
||||
a_black_point_found_on_border = true;
|
||||
at_least_one_black_point_found_on_top = true;
|
||||
} else if !at_least_one_black_point_found_on_top {
|
||||
up -= 1;
|
||||
}
|
||||
}
|
||||
if up < 0 {
|
||||
size_exceeded = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if !size_exceeded {
|
||||
let max_size: i32 = right - left;
|
||||
let mut z: ResultPoint = null;
|
||||
{
|
||||
let mut i: i32 = 1;
|
||||
while z == null && i < max_size {
|
||||
{
|
||||
z = self.get_black_point_on_segment(left, down - i, left + i, down);
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
if z == null {
|
||||
throw NotFoundException::get_not_found_instance();
|
||||
}
|
||||
let mut t: ResultPoint = null;
|
||||
//go down right
|
||||
{
|
||||
let mut i: i32 = 1;
|
||||
while t == null && i < max_size {
|
||||
{
|
||||
t = self.get_black_point_on_segment(left, up + i, left + i, up);
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
if t == null {
|
||||
throw NotFoundException::get_not_found_instance();
|
||||
}
|
||||
let mut x: ResultPoint = null;
|
||||
//go down left
|
||||
{
|
||||
let mut i: i32 = 1;
|
||||
while x == null && i < max_size {
|
||||
{
|
||||
x = self.get_black_point_on_segment(right, up + i, right - i, up);
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
if x == null {
|
||||
throw NotFoundException::get_not_found_instance();
|
||||
}
|
||||
let mut y: ResultPoint = null;
|
||||
//go up left
|
||||
{
|
||||
let mut i: i32 = 1;
|
||||
while y == null && i < max_size {
|
||||
{
|
||||
y = self.get_black_point_on_segment(right, down - i, right - i, down);
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
if y == null {
|
||||
throw NotFoundException::get_not_found_instance();
|
||||
}
|
||||
return Ok(self.center_edges(y, z, x, t));
|
||||
} else {
|
||||
throw NotFoundException::get_not_found_instance();
|
||||
}
|
||||
}
|
||||
|
||||
fn get_black_point_on_segment(&self, a_x: f32, a_y: f32, b_x: f32, b_y: f32) -> ResultPoint {
|
||||
let dist: i32 = MathUtils::round(&MathUtils::distance(a_x, a_y, b_x, b_y));
|
||||
let x_step: f32 = (b_x - a_x) / dist;
|
||||
let y_step: f32 = (b_y - a_y) / dist;
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < dist {
|
||||
{
|
||||
let x: i32 = MathUtils::round(a_x + i * x_step);
|
||||
let y: i32 = MathUtils::round(a_y + i * y_step);
|
||||
if self.image.get(x, y) {
|
||||
return ResultPoint::new(x, y);
|
||||
}
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* recenters the points of a constant distance towards the center
|
||||
*
|
||||
* @param y bottom most point
|
||||
* @param z left most point
|
||||
* @param x right most point
|
||||
* @param t top most point
|
||||
* @return {@link ResultPoint}[] describing the corners of the rectangular
|
||||
* region. The first and last points are opposed on the diagonal, as
|
||||
* are the second and third. The first point will be the topmost
|
||||
* point and the last, the bottommost. The second point will be
|
||||
* leftmost and the third, the rightmost
|
||||
*/
|
||||
fn center_edges(&self, y: &ResultPoint, z: &ResultPoint, x: &ResultPoint, t: &ResultPoint) -> Vec<ResultPoint> {
|
||||
//
|
||||
// t t
|
||||
// z x
|
||||
// x OR z
|
||||
// y y
|
||||
//
|
||||
let yi: f32 = y.get_x();
|
||||
let yj: f32 = y.get_y();
|
||||
let zi: f32 = z.get_x();
|
||||
let zj: f32 = z.get_y();
|
||||
let xi: f32 = x.get_x();
|
||||
let xj: f32 = x.get_y();
|
||||
let ti: f32 = t.get_x();
|
||||
let tj: f32 = t.get_y();
|
||||
if yi < self.width / 2.0f {
|
||||
return : vec![ResultPoint; 4] = vec![ResultPoint::new(ti - CORR, tj + CORR), ResultPoint::new(zi + CORR, zj + CORR), ResultPoint::new(xi - CORR, xj - CORR), ResultPoint::new(yi + CORR, yj - CORR), ]
|
||||
;
|
||||
} else {
|
||||
return : vec![ResultPoint; 4] = vec![ResultPoint::new(ti + CORR, tj + CORR), ResultPoint::new(zi + CORR, zj - CORR), ResultPoint::new(xi - CORR, xj + CORR), ResultPoint::new(yi - CORR, yj - CORR), ]
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether a segment contains a black point
|
||||
*
|
||||
* @param a min value of the scanned coordinate
|
||||
* @param b max value of the scanned coordinate
|
||||
* @param fixed value of fixed coordinate
|
||||
* @param horizontal set to true if scan must be horizontal, false if vertical
|
||||
* @return true if a black point has been found, else false.
|
||||
*/
|
||||
fn contains_black_point(&self, a: i32, b: i32, fixed: i32, horizontal: bool) -> bool {
|
||||
if horizontal {
|
||||
{
|
||||
let mut x: i32 = a;
|
||||
while x <= b {
|
||||
{
|
||||
if self.image.get(x, fixed) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
x += 1;
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
{
|
||||
let mut y: i32 = a;
|
||||
while y <= b {
|
||||
{
|
||||
if self.image.get(fixed, y) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
y += 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
47
port_src/output/zxing/common/detector_result.rs
Normal file
47
port_src/output/zxing/common/detector_result.rs
Normal file
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* 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::common;
|
||||
|
||||
/**
|
||||
* <p>Encapsulates the result of detecting a barcode in an image. This includes the raw
|
||||
* matrix of black/white pixels corresponding to the barcode, and possibly points of interest
|
||||
* in the image, like the location of finder patterns or corners of the barcode in the image.</p>
|
||||
*
|
||||
* @author Sean Owen
|
||||
*/
|
||||
pub struct DetectorResult {
|
||||
|
||||
let bits: BitMatrix;
|
||||
|
||||
let points: Vec<ResultPoint>;
|
||||
}
|
||||
|
||||
impl DetectorResult {
|
||||
|
||||
pub fn new( bits: &BitMatrix, points: &Vec<ResultPoint>) -> DetectorResult {
|
||||
let .bits = bits;
|
||||
let .points = points;
|
||||
}
|
||||
|
||||
pub fn get_bits(&self) -> BitMatrix {
|
||||
return self.bits;
|
||||
}
|
||||
|
||||
pub fn get_points(&self) -> Vec<ResultPoint> {
|
||||
return self.points;
|
||||
}
|
||||
}
|
||||
|
||||
194
port_src/output/zxing/common/e_c_i_encoder_set.rs
Normal file
194
port_src/output/zxing/common/e_c_i_encoder_set.rs
Normal file
@@ -0,0 +1,194 @@
|
||||
/*
|
||||
* Copyright 2021 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::common;
|
||||
|
||||
/**
|
||||
* Set of CharsetEncoders for a given input string
|
||||
*
|
||||
* Invariants:
|
||||
* - The list contains only encoders from CharacterSetECI (list is shorter then the list of encoders available on
|
||||
* the platform for which ECI values are defined).
|
||||
* - The list contains encoders at least one encoder for every character in the input.
|
||||
* - The first encoder in the list is always the ISO-8859-1 encoder even of no character in the input can be encoded
|
||||
* by it.
|
||||
* - If the input contains a character that is not in ISO-8859-1 then the last two entries in the list will be the
|
||||
* UTF-8 encoder and the UTF-16BE encoder.
|
||||
*
|
||||
* @author Alex Geller
|
||||
*/
|
||||
|
||||
// List of encoders that potentially encode characters not in ISO-8859-1 in one byte.
|
||||
const ENCODERS: List<CharsetEncoder> = ArrayList<>::new();
|
||||
pub struct ECIEncoderSet {
|
||||
|
||||
let mut encoders: Vec<CharsetEncoder>;
|
||||
|
||||
let priority_encoder_index: i32;
|
||||
}
|
||||
|
||||
impl ECIEncoderSet {
|
||||
|
||||
static {
|
||||
let names: vec![Vec<String>; 20] = vec!["IBM437", "ISO-8859-2", "ISO-8859-3", "ISO-8859-4", "ISO-8859-5", "ISO-8859-6", "ISO-8859-7", "ISO-8859-8", "ISO-8859-9", "ISO-8859-10", "ISO-8859-11", "ISO-8859-13", "ISO-8859-14", "ISO-8859-15", "ISO-8859-16", "windows-1250", "windows-1251", "windows-1252", "windows-1256", "Shift_JIS", ]
|
||||
;
|
||||
for let name: String in names {
|
||||
if CharacterSetECI::get_character_set_e_c_i_by_name(&name) != null {
|
||||
let tryResult1 = 0;
|
||||
'try1: loop {
|
||||
{
|
||||
ENCODERS::add(&Charset::for_name(&name)::new_encoder());
|
||||
}
|
||||
break 'try1
|
||||
}
|
||||
match tryResult1 {
|
||||
catch ( e: &UnsupportedCharsetException) {
|
||||
} 0 => break
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an encoder set
|
||||
*
|
||||
* @param stringToEncode the string that needs to be encoded
|
||||
* @param priorityCharset The preferred {@link Charset} or null.
|
||||
* @param fnc1 fnc1 denotes the character in the input that represents the FNC1 character or -1 for a non-GS1 bar
|
||||
* code. When specified, it is considered an error to pass it as argument to the methods canEncode() or encode().
|
||||
*/
|
||||
pub fn new( string_to_encode: &String, priority_charset: &Charset, fnc1: i32) -> ECIEncoderSet {
|
||||
let needed_encoders: List<CharsetEncoder> = ArrayList<>::new();
|
||||
//we always need the ISO-8859-1 encoder. It is the default encoding
|
||||
needed_encoders.add(&StandardCharsets::ISO_8859_1::new_encoder());
|
||||
let need_unicode_encoder: bool = priority_charset != null && priority_charset.name().starts_with("UTF");
|
||||
//Walk over the input string and see if all characters can be encoded with the list of encoders
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < string_to_encode.length() {
|
||||
{
|
||||
let can_encode: bool = false;
|
||||
for let encoder: CharsetEncoder in needed_encoders {
|
||||
let c: char = string_to_encode.char_at(i);
|
||||
if c == fnc1 || encoder.can_encode(c) {
|
||||
can_encode = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if !can_encode {
|
||||
//for the character at position i we don't yet have an encoder in the list
|
||||
for let encoder: CharsetEncoder in ENCODERS {
|
||||
if encoder.can_encode(&string_to_encode.char_at(i)) {
|
||||
//Good, we found an encoder that can encode the character. We add him to the list and continue scanning
|
||||
//the input
|
||||
needed_encoders.add(&encoder);
|
||||
can_encode = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if !can_encode {
|
||||
//The character is not encodeable by any of the single byte encoders so we remember that we will need a
|
||||
//Unicode encoder.
|
||||
need_unicode_encoder = true;
|
||||
}
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
if needed_encoders.size() == 1 && !need_unicode_encoder {
|
||||
//the entire input can be encoded by the ISO-8859-1 encoder
|
||||
encoders = : vec![CharsetEncoder; 1] = vec![needed_encoders.get(0), ]
|
||||
;
|
||||
} else {
|
||||
// we need more than one single byte encoder or we need a Unicode encoder.
|
||||
// In this case we append a UTF-8 and UTF-16 encoder to the list
|
||||
encoders = : [Option<CharsetEncoder>; needed_encoders.size() + 2] = [None; needed_encoders.size() + 2];
|
||||
let mut index: i32 = 0;
|
||||
for let encoder: CharsetEncoder in needed_encoders {
|
||||
encoders[index += 1 !!!check!!! post increment] = encoder;
|
||||
}
|
||||
encoders[index] = StandardCharsets::UTF_8::new_encoder();
|
||||
encoders[index + 1] = StandardCharsets::UTF_16BE::new_encoder();
|
||||
}
|
||||
//Compute priorityEncoderIndex by looking up priorityCharset in encoders
|
||||
let priority_encoder_index_value: i32 = -1;
|
||||
if priority_charset != null {
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < encoders.len() {
|
||||
{
|
||||
if encoders[i] != null && priority_charset.name().equals(&encoders[i].charset().name()) {
|
||||
priority_encoder_index_value = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
priority_encoder_index = priority_encoder_index_value;
|
||||
//invariants
|
||||
assert!( encoders[0].charset().equals(StandardCharsets::ISO_8859_1));
|
||||
}
|
||||
|
||||
pub fn length(&self) -> i32 {
|
||||
return self.encoders.len();
|
||||
}
|
||||
|
||||
pub fn get_charset_name(&self, index: i32) -> String {
|
||||
assert!( index < self.length());
|
||||
return self.encoders[index].charset().name();
|
||||
}
|
||||
|
||||
pub fn get_charset(&self, index: i32) -> Charset {
|
||||
assert!( index < self.length());
|
||||
return self.encoders[index].charset();
|
||||
}
|
||||
|
||||
pub fn get_e_c_i_value(&self, encoder_index: i32) -> i32 {
|
||||
return CharacterSetECI::get_character_set_e_c_i(&self.encoders[encoder_index].charset())::get_value();
|
||||
}
|
||||
|
||||
/*
|
||||
* returns -1 if no priority charset was defined
|
||||
*/
|
||||
pub fn get_priority_encoder_index(&self) -> i32 {
|
||||
return self.priority_encoder_index;
|
||||
}
|
||||
|
||||
pub fn can_encode(&self, c: char, encoder_index: i32) -> bool {
|
||||
assert!( encoder_index < self.length());
|
||||
let encoder: CharsetEncoder = self.encoders[encoder_index];
|
||||
return encoder.can_encode(format!("{}", c));
|
||||
}
|
||||
|
||||
pub fn encode(&self, c: char, encoder_index: i32) -> Vec<i8> {
|
||||
assert!( encoder_index < self.length());
|
||||
let encoder: CharsetEncoder = self.encoders[encoder_index];
|
||||
assert!( encoder.can_encode(format!("{}", c)));
|
||||
return (format!("{}", c)).get_bytes(&encoder.charset());
|
||||
}
|
||||
|
||||
pub fn encode(&self, s: &String, encoder_index: i32) -> Vec<i8> {
|
||||
assert!( encoder_index < self.length());
|
||||
let encoder: CharsetEncoder = self.encoders[encoder_index];
|
||||
return s.get_bytes(&encoder.charset());
|
||||
}
|
||||
}
|
||||
|
||||
108
port_src/output/zxing/common/e_c_i_input.rs
Normal file
108
port_src/output/zxing/common/e_c_i_input.rs
Normal file
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* Copyright 2021 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::common;
|
||||
|
||||
/**
|
||||
* Interface to navigate a sequence of ECIs and bytes.
|
||||
*
|
||||
* @author Alex Geller
|
||||
*/
|
||||
pub trait ECIInput {
|
||||
|
||||
/**
|
||||
* Returns the length of this input. The length is the number
|
||||
* of {@code byte}s in or ECIs in the sequence.
|
||||
*
|
||||
* @return the number of {@code char}s in this sequence
|
||||
*/
|
||||
fn length(&self) -> i32 ;
|
||||
|
||||
/**
|
||||
* Returns the {@code byte} value at the specified index. An index ranges from zero
|
||||
* to {@code length() - 1}. The first {@code byte} value of the sequence is at
|
||||
* index zero, the next at index one, and so on, as for array
|
||||
* indexing.
|
||||
*
|
||||
* @param index the index of the {@code byte} value to be returned
|
||||
*
|
||||
* @return the specified {@code byte} value as character or the FNC1 character
|
||||
*
|
||||
* @throws IndexOutOfBoundsException
|
||||
* if the {@code index} argument is negative or not less than
|
||||
* {@code length()}
|
||||
* @throws IllegalArgumentException
|
||||
* if the value at the {@code index} argument is an ECI (@see #isECI)
|
||||
*/
|
||||
fn char_at(&self, index: i32) -> char ;
|
||||
|
||||
/**
|
||||
* Returns a {@code CharSequence} that is a subsequence of this sequence.
|
||||
* The subsequence starts with the {@code char} value at the specified index and
|
||||
* ends with the {@code char} value at index {@code end - 1}. The length
|
||||
* (in {@code char}s) of the
|
||||
* returned sequence is {@code end - start}, so if {@code start == end}
|
||||
* then an empty sequence is returned.
|
||||
*
|
||||
* @param start the start index, inclusive
|
||||
* @param end the end index, exclusive
|
||||
*
|
||||
* @return the specified subsequence
|
||||
*
|
||||
* @throws IndexOutOfBoundsException
|
||||
* if {@code start} or {@code end} are negative,
|
||||
* if {@code end} is greater than {@code length()},
|
||||
* or if {@code start} is greater than {@code end}
|
||||
* @throws IllegalArgumentException
|
||||
* if a value in the range {@code start}-{@code end} is an ECI (@see #isECI)
|
||||
*/
|
||||
fn sub_sequence(&self, start: i32, end: i32) -> CharSequence ;
|
||||
|
||||
/**
|
||||
* Determines if a value is an ECI
|
||||
*
|
||||
* @param index the index of the value
|
||||
*
|
||||
* @return true if the value at position {@code index} is an ECI
|
||||
*
|
||||
* @throws IndexOutOfBoundsException
|
||||
* if the {@code index} argument is negative or not less than
|
||||
* {@code length()}
|
||||
*/
|
||||
fn is_e_c_i(&self, index: i32) -> bool ;
|
||||
|
||||
/**
|
||||
* Returns the {@code int} ECI value at the specified index. An index ranges from zero
|
||||
* to {@code length() - 1}. The first {@code byte} value of the sequence is at
|
||||
* index zero, the next at index one, and so on, as for array
|
||||
* indexing.
|
||||
*
|
||||
* @param index the index of the {@code int} value to be returned
|
||||
*
|
||||
* @return the specified {@code int} ECI value.
|
||||
* The ECI specified the encoding of all bytes with a higher index until the
|
||||
* next ECI or until the end of the input if no other ECI follows.
|
||||
*
|
||||
* @throws IndexOutOfBoundsException
|
||||
* if the {@code index} argument is negative or not less than
|
||||
* {@code length()}
|
||||
* @throws IllegalArgumentException
|
||||
* if the value at the {@code index} argument is not an ECI (@see #isECI)
|
||||
*/
|
||||
fn get_e_c_i_value(&self, index: i32) -> i32 ;
|
||||
|
||||
fn have_n_characters(&self, index: i32, n: i32) -> bool ;
|
||||
}
|
||||
|
||||
146
port_src/output/zxing/common/e_c_i_string_builder.rs
Normal file
146
port_src/output/zxing/common/e_c_i_string_builder.rs
Normal file
@@ -0,0 +1,146 @@
|
||||
/*
|
||||
* 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::common;
|
||||
|
||||
/**
|
||||
* Class that converts a sequence of ECIs and bytes into a string
|
||||
*
|
||||
* @author Alex Geller
|
||||
*/
|
||||
pub struct ECIStringBuilder {
|
||||
|
||||
let current_bytes: StringBuilder;
|
||||
|
||||
let mut result: StringBuilder;
|
||||
|
||||
let current_charset: Charset = StandardCharsets::ISO_8859_1;
|
||||
}
|
||||
|
||||
impl ECIStringBuilder {
|
||||
|
||||
pub fn new() -> ECIStringBuilder {
|
||||
current_bytes = StringBuilder::new();
|
||||
}
|
||||
|
||||
pub fn new( initial_capacity: i32) -> ECIStringBuilder {
|
||||
current_bytes = StringBuilder::new(initial_capacity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends {@code value} as a byte value
|
||||
*
|
||||
* @param value character whose lowest byte is to be appended
|
||||
*/
|
||||
pub fn append(&self, value: char) {
|
||||
self.current_bytes.append((value & 0xff) as char);
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends {@code value} as a byte value
|
||||
*
|
||||
* @param value byte to append
|
||||
*/
|
||||
pub fn append(&self, value: i8) {
|
||||
self.current_bytes.append((value & 0xff) as char);
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends the characters in {@code value} as bytes values
|
||||
*
|
||||
* @param value string to append
|
||||
*/
|
||||
pub fn append(&self, value: &String) {
|
||||
self.current_bytes.append(&value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Append the string repesentation of {@code value} (short for {@code append(String.valueOf(value))})
|
||||
*
|
||||
* @param value int to append as a string
|
||||
*/
|
||||
pub fn append(&self, value: i32) {
|
||||
self.append(&String::value_of(value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends ECI value to output.
|
||||
*
|
||||
* @param value ECI value to append, as an int
|
||||
* @throws FormatException on invalid ECI value
|
||||
*/
|
||||
pub fn append_e_c_i(&self, value: i32) -> /* throws FormatException */Result<Void, Rc<Exception>> {
|
||||
self.encode_current_bytes_if_any();
|
||||
let character_set_e_c_i: CharacterSetECI = CharacterSetECI::get_character_set_e_c_i_by_value(value);
|
||||
if character_set_e_c_i == null {
|
||||
throw FormatException::get_format_instance();
|
||||
}
|
||||
self.current_charset = character_set_e_c_i.get_charset();
|
||||
}
|
||||
|
||||
fn encode_current_bytes_if_any(&self) {
|
||||
if self.current_charset.equals(StandardCharsets::ISO_8859_1) {
|
||||
if self.current_bytes.length() > 0 {
|
||||
if self.result == null {
|
||||
self.result = self.current_bytes;
|
||||
self.current_bytes = StringBuilder::new();
|
||||
} else {
|
||||
self.result.append(&self.current_bytes);
|
||||
self.current_bytes = StringBuilder::new();
|
||||
}
|
||||
}
|
||||
} else if self.current_bytes.length() > 0 {
|
||||
let bytes: Vec<i8> = self.current_bytes.to_string().get_bytes(StandardCharsets::ISO_8859_1);
|
||||
self.current_bytes = StringBuilder::new();
|
||||
if self.result == null {
|
||||
self.result = StringBuilder::new(String::new(&bytes, &self.current_charset));
|
||||
} else {
|
||||
self.result.append(String::new(&bytes, &self.current_charset));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends the characters from {@code value} (unlike all other append methods of this class who append bytes)
|
||||
*
|
||||
* @param value characters to append
|
||||
*/
|
||||
pub fn append_characters(&self, value: &StringBuilder) {
|
||||
self.encode_current_bytes_if_any();
|
||||
self.result.append(&value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Short for {@code toString().length()} (if possible, use {@link #isEmpty()} instead)
|
||||
*
|
||||
* @return length of string representation in characters
|
||||
*/
|
||||
pub fn length(&self) -> i32 {
|
||||
return self.to_string().length();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true iff nothing has been appended
|
||||
*/
|
||||
pub fn is_empty(&self) -> bool {
|
||||
return self.current_bytes.length() == 0 && (self.result == null || self.result.length() == 0);
|
||||
}
|
||||
|
||||
pub fn to_string(&self) -> String {
|
||||
self.encode_current_bytes_if_any();
|
||||
return if self.result == null { "" } else { self.result.to_string() };
|
||||
}
|
||||
}
|
||||
|
||||
269
port_src/output/zxing/common/global_histogram_binarizer.rs
Normal file
269
port_src/output/zxing/common/global_histogram_binarizer.rs
Normal file
@@ -0,0 +1,269 @@
|
||||
/*
|
||||
* 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::common;
|
||||
|
||||
/**
|
||||
* This Binarizer implementation uses the old ZXing global histogram approach. It is suitable
|
||||
* for low-end mobile devices which don't have enough CPU or memory to use a local thresholding
|
||||
* algorithm. However, because it picks a global black point, it cannot handle difficult shadows
|
||||
* and gradients.
|
||||
*
|
||||
* Faster mobile devices and all desktop applications should probably use HybridBinarizer instead.
|
||||
*
|
||||
* @author dswitkin@google.com (Daniel Switkin)
|
||||
* @author Sean Owen
|
||||
*/
|
||||
|
||||
const LUMINANCE_BITS: i32 = 5;
|
||||
|
||||
const LUMINANCE_SHIFT: i32 = 8 - LUMINANCE_BITS;
|
||||
|
||||
const LUMINANCE_BUCKETS: i32 = 1 << LUMINANCE_BITS;
|
||||
|
||||
const EMPTY: [i8; 0] = [0; 0];
|
||||
pub struct GlobalHistogramBinarizer {
|
||||
super: Binarizer;
|
||||
|
||||
let mut luminances: Vec<i8>;
|
||||
|
||||
let mut buckets: Vec<i32>;
|
||||
}
|
||||
|
||||
impl GlobalHistogramBinarizer {
|
||||
|
||||
pub fn new( source: &LuminanceSource) -> GlobalHistogramBinarizer {
|
||||
super(source);
|
||||
luminances = EMPTY;
|
||||
buckets = : [i32; LUMINANCE_BUCKETS] = [0; LUMINANCE_BUCKETS];
|
||||
}
|
||||
|
||||
// Applies simple sharpening to the row data to improve performance of the 1D Readers.
|
||||
pub fn get_black_row(&self, y: i32, row: &BitArray) -> /* throws NotFoundException */Result<BitArray, Rc<Exception>> {
|
||||
let source: LuminanceSource = get_luminance_source();
|
||||
let width: i32 = source.get_width();
|
||||
if row == null || row.get_size() < width {
|
||||
row = BitArray::new(width);
|
||||
} else {
|
||||
row.clear();
|
||||
}
|
||||
self.init_arrays(width);
|
||||
let local_luminances: Vec<i8> = source.get_row(y, &self.luminances);
|
||||
let local_buckets: Vec<i32> = self.buckets;
|
||||
{
|
||||
let mut x: i32 = 0;
|
||||
while x < width {
|
||||
{
|
||||
local_buckets[(local_luminances[x] & 0xff) >> LUMINANCE_SHIFT] += 1;
|
||||
}
|
||||
x += 1;
|
||||
}
|
||||
}
|
||||
|
||||
let black_point: i32 = ::estimate_black_point(&local_buckets);
|
||||
if width < 3 {
|
||||
// Special case for very small images
|
||||
{
|
||||
let mut x: i32 = 0;
|
||||
while x < width {
|
||||
{
|
||||
if (local_luminances[x] & 0xff) < black_point {
|
||||
row.set(x);
|
||||
}
|
||||
}
|
||||
x += 1;
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
let mut left: i32 = local_luminances[0] & 0xff;
|
||||
let mut center: i32 = local_luminances[1] & 0xff;
|
||||
{
|
||||
let mut x: i32 = 1;
|
||||
while x < width - 1 {
|
||||
{
|
||||
let right: i32 = local_luminances[x + 1] & 0xff;
|
||||
// A simple -1 4 -1 box filter with a weight of 2.
|
||||
if ((center * 4) - left - right) / 2 < black_point {
|
||||
row.set(x);
|
||||
}
|
||||
left = center;
|
||||
center = right;
|
||||
}
|
||||
x += 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return Ok(row);
|
||||
}
|
||||
|
||||
// Does not sharpen the data, as this call is intended to only be used by 2D Readers.
|
||||
pub fn get_black_matrix(&self) -> /* throws NotFoundException */Result<BitMatrix, Rc<Exception>> {
|
||||
let source: LuminanceSource = get_luminance_source();
|
||||
let width: i32 = source.get_width();
|
||||
let height: i32 = source.get_height();
|
||||
let matrix: BitMatrix = BitMatrix::new(width, height);
|
||||
// Quickly calculates the histogram by sampling four rows from the image. This proved to be
|
||||
// more robust on the blackbox tests than sampling a diagonal as we used to do.
|
||||
self.init_arrays(width);
|
||||
let local_buckets: Vec<i32> = self.buckets;
|
||||
{
|
||||
let mut y: i32 = 1;
|
||||
while y < 5 {
|
||||
{
|
||||
let row: i32 = height * y / 5;
|
||||
let local_luminances: Vec<i8> = source.get_row(row, &self.luminances);
|
||||
let right: i32 = (width * 4) / 5;
|
||||
{
|
||||
let mut x: i32 = width / 5;
|
||||
while x < right {
|
||||
{
|
||||
let mut pixel: i32 = local_luminances[x] & 0xff;
|
||||
local_buckets[pixel >> LUMINANCE_SHIFT] += 1;
|
||||
}
|
||||
x += 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
y += 1;
|
||||
}
|
||||
}
|
||||
|
||||
let black_point: i32 = ::estimate_black_point(&local_buckets);
|
||||
// We delay reading the entire image luminance until the black point estimation succeeds.
|
||||
// Although we end up reading four rows twice, it is consistent with our motto of
|
||||
// "fail quickly" which is necessary for continuous scanning.
|
||||
let local_luminances: Vec<i8> = source.get_matrix();
|
||||
{
|
||||
let mut y: i32 = 0;
|
||||
while y < height {
|
||||
{
|
||||
let offset: i32 = y * width;
|
||||
{
|
||||
let mut x: i32 = 0;
|
||||
while x < width {
|
||||
{
|
||||
let pixel: i32 = local_luminances[offset + x] & 0xff;
|
||||
if pixel < black_point {
|
||||
matrix.set(x, y);
|
||||
}
|
||||
}
|
||||
x += 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
y += 1;
|
||||
}
|
||||
}
|
||||
|
||||
return Ok(matrix);
|
||||
}
|
||||
|
||||
pub fn create_binarizer(&self, source: &LuminanceSource) -> Binarizer {
|
||||
return GlobalHistogramBinarizer::new(source);
|
||||
}
|
||||
|
||||
fn init_arrays(&self, luminance_size: i32) {
|
||||
if self.luminances.len() < luminance_size {
|
||||
self.luminances = : [i8; luminance_size] = [0; luminance_size];
|
||||
}
|
||||
{
|
||||
let mut x: i32 = 0;
|
||||
while x < LUMINANCE_BUCKETS {
|
||||
{
|
||||
self.buckets[x] = 0;
|
||||
}
|
||||
x += 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fn estimate_black_point( buckets: &Vec<i32>) -> /* throws NotFoundException */Result<i32, Rc<Exception>> {
|
||||
// Find the tallest peak in the histogram.
|
||||
let num_buckets: i32 = buckets.len();
|
||||
let max_bucket_count: i32 = 0;
|
||||
let first_peak: i32 = 0;
|
||||
let first_peak_size: i32 = 0;
|
||||
{
|
||||
let mut x: i32 = 0;
|
||||
while x < num_buckets {
|
||||
{
|
||||
if buckets[x] > first_peak_size {
|
||||
first_peak = x;
|
||||
first_peak_size = buckets[x];
|
||||
}
|
||||
if buckets[x] > max_bucket_count {
|
||||
max_bucket_count = buckets[x];
|
||||
}
|
||||
}
|
||||
x += 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Find the second-tallest peak which is somewhat far from the tallest peak.
|
||||
let second_peak: i32 = 0;
|
||||
let second_peak_score: i32 = 0;
|
||||
{
|
||||
let mut x: i32 = 0;
|
||||
while x < num_buckets {
|
||||
{
|
||||
let distance_to_biggest: i32 = x - first_peak;
|
||||
// Encourage more distant second peaks by multiplying by square of distance.
|
||||
let score: i32 = buckets[x] * distance_to_biggest * distance_to_biggest;
|
||||
if score > second_peak_score {
|
||||
second_peak = x;
|
||||
second_peak_score = score;
|
||||
}
|
||||
}
|
||||
x += 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure firstPeak corresponds to the black peak.
|
||||
if first_peak > second_peak {
|
||||
let temp: i32 = first_peak;
|
||||
first_peak = second_peak;
|
||||
second_peak = temp;
|
||||
}
|
||||
// than waste time trying to decode the image, and risk false positives.
|
||||
if second_peak - first_peak <= num_buckets / 16 {
|
||||
throw NotFoundException::get_not_found_instance();
|
||||
}
|
||||
// Find a valley between them that is low and closer to the white peak.
|
||||
let best_valley: i32 = second_peak - 1;
|
||||
let best_valley_score: i32 = -1;
|
||||
{
|
||||
let mut x: i32 = second_peak - 1;
|
||||
while x > first_peak {
|
||||
{
|
||||
let from_first: i32 = x - first_peak;
|
||||
let score: i32 = from_first * from_first * (second_peak - x) * (max_bucket_count - buckets[x]);
|
||||
if score > best_valley_score {
|
||||
best_valley = x;
|
||||
best_valley_score = score;
|
||||
}
|
||||
}
|
||||
x -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
return Ok(best_valley << LUMINANCE_SHIFT);
|
||||
}
|
||||
}
|
||||
|
||||
175
port_src/output/zxing/common/grid_sampler.rs
Normal file
175
port_src/output/zxing/common/grid_sampler.rs
Normal file
@@ -0,0 +1,175 @@
|
||||
/*
|
||||
* 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::common;
|
||||
|
||||
/**
|
||||
* Implementations of this class can, given locations of finder patterns for a QR code in an
|
||||
* image, sample the right points in the image to reconstruct the QR code, accounting for
|
||||
* perspective distortion. It is abstracted since it is relatively expensive and should be allowed
|
||||
* to take advantage of platform-specific optimized implementations, like Sun's Java Advanced
|
||||
* Imaging library, but which may not be available in other environments such as J2ME, and vice
|
||||
* versa.
|
||||
*
|
||||
* The implementation used can be controlled by calling {@link #setGridSampler(GridSampler)}
|
||||
* with an instance of a class which implements this interface.
|
||||
*
|
||||
* @author Sean Owen
|
||||
*/
|
||||
|
||||
let grid_sampler: GridSampler = DefaultGridSampler::new();
|
||||
pub struct GridSampler {
|
||||
}
|
||||
|
||||
impl GridSampler {
|
||||
|
||||
/**
|
||||
* Sets the implementation of GridSampler used by the library. One global
|
||||
* instance is stored, which may sound problematic. But, the implementation provided
|
||||
* ought to be appropriate for the entire platform, and all uses of this library
|
||||
* in the whole lifetime of the JVM. For instance, an Android activity can swap in
|
||||
* an implementation that takes advantage of native platform libraries.
|
||||
*
|
||||
* @param newGridSampler The platform-specific object to install.
|
||||
*/
|
||||
pub fn set_grid_sampler( new_grid_sampler: &GridSampler) {
|
||||
grid_sampler = new_grid_sampler;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the current implementation of GridSampler
|
||||
*/
|
||||
pub fn get_instance() -> GridSampler {
|
||||
return grid_sampler;
|
||||
}
|
||||
|
||||
/**
|
||||
* Samples an image for a rectangular matrix of bits of the given dimension. The sampling
|
||||
* transformation is determined by the coordinates of 4 points, in the original and transformed
|
||||
* image space.
|
||||
*
|
||||
* @param image image to sample
|
||||
* @param dimensionX width of {@link BitMatrix} to sample from image
|
||||
* @param dimensionY height of {@link BitMatrix} to sample from image
|
||||
* @param p1ToX point 1 preimage X
|
||||
* @param p1ToY point 1 preimage Y
|
||||
* @param p2ToX point 2 preimage X
|
||||
* @param p2ToY point 2 preimage Y
|
||||
* @param p3ToX point 3 preimage X
|
||||
* @param p3ToY point 3 preimage Y
|
||||
* @param p4ToX point 4 preimage X
|
||||
* @param p4ToY point 4 preimage Y
|
||||
* @param p1FromX point 1 image X
|
||||
* @param p1FromY point 1 image Y
|
||||
* @param p2FromX point 2 image X
|
||||
* @param p2FromY point 2 image Y
|
||||
* @param p3FromX point 3 image X
|
||||
* @param p3FromY point 3 image Y
|
||||
* @param p4FromX point 4 image X
|
||||
* @param p4FromY point 4 image Y
|
||||
* @return {@link BitMatrix} representing a grid of points sampled from the image within a region
|
||||
* defined by the "from" parameters
|
||||
* @throws NotFoundException if image can't be sampled, for example, if the transformation defined
|
||||
* by the given points is invalid or results in sampling outside the image boundaries
|
||||
*/
|
||||
pub fn sample_grid(&self, image: &BitMatrix, dimension_x: i32, dimension_y: i32, p1_to_x: f32, p1_to_y: f32, p2_to_x: f32, p2_to_y: f32, p3_to_x: f32, p3_to_y: f32, p4_to_x: f32, p4_to_y: f32, p1_from_x: f32, p1_from_y: f32, p2_from_x: f32, p2_from_y: f32, p3_from_x: f32, p3_from_y: f32, p4_from_x: f32, p4_from_y: f32) -> /* throws NotFoundException */Result<BitMatrix, Rc<Exception>> ;
|
||||
|
||||
pub fn sample_grid(&self, image: &BitMatrix, dimension_x: i32, dimension_y: i32, transform: &PerspectiveTransform) -> /* throws NotFoundException */Result<BitMatrix, Rc<Exception>> ;
|
||||
|
||||
/**
|
||||
* <p>Checks a set of points that have been transformed to sample points on an image against
|
||||
* the image's dimensions to see if the point are even within the image.</p>
|
||||
*
|
||||
* <p>This method will actually "nudge" the endpoints back onto the image if they are found to be
|
||||
* barely (less than 1 pixel) off the image. This accounts for imperfect detection of finder
|
||||
* patterns in an image where the QR Code runs all the way to the image border.</p>
|
||||
*
|
||||
* <p>For efficiency, the method will check points from either end of the line until one is found
|
||||
* to be within the image. Because the set of points are assumed to be linear, this is valid.</p>
|
||||
*
|
||||
* @param image image into which the points should map
|
||||
* @param points actual points in x1,y1,...,xn,yn form
|
||||
* @throws NotFoundException if an endpoint is lies outside the image boundaries
|
||||
*/
|
||||
pub fn check_and_nudge_points( image: &BitMatrix, points: &Vec<f32>) -> /* throws NotFoundException */Result<Void, Rc<Exception>> {
|
||||
let width: i32 = image.get_width();
|
||||
let height: i32 = image.get_height();
|
||||
// Check and nudge points from start until we see some that are OK:
|
||||
let mut nudged: bool = true;
|
||||
// points.length must be even
|
||||
let max_offset: i32 = points.len() - 1;
|
||||
{
|
||||
let mut offset: i32 = 0;
|
||||
while offset < max_offset && nudged {
|
||||
{
|
||||
let x: i32 = points[offset] as i32;
|
||||
let y: i32 = points[offset + 1] as i32;
|
||||
if x < -1 || x > width || y < -1 || y > height {
|
||||
throw NotFoundException::get_not_found_instance();
|
||||
}
|
||||
nudged = false;
|
||||
if x == -1 {
|
||||
points[offset] = 0.0f;
|
||||
nudged = true;
|
||||
} else if x == width {
|
||||
points[offset] = width - 1.0;
|
||||
nudged = true;
|
||||
}
|
||||
if y == -1 {
|
||||
points[offset + 1] = 0.0f;
|
||||
nudged = true;
|
||||
} else if y == height {
|
||||
points[offset + 1] = height - 1.0;
|
||||
nudged = true;
|
||||
}
|
||||
}
|
||||
offset += 2;
|
||||
}
|
||||
}
|
||||
|
||||
// Check and nudge points from end:
|
||||
nudged = true;
|
||||
{
|
||||
let mut offset: i32 = points.len() - 2;
|
||||
while offset >= 0 && nudged {
|
||||
{
|
||||
let x: i32 = points[offset] as i32;
|
||||
let y: i32 = points[offset + 1] as i32;
|
||||
if x < -1 || x > width || y < -1 || y > height {
|
||||
throw NotFoundException::get_not_found_instance();
|
||||
}
|
||||
nudged = false;
|
||||
if x == -1 {
|
||||
points[offset] = 0.0f;
|
||||
nudged = true;
|
||||
} else if x == width {
|
||||
points[offset] = width - 1.0;
|
||||
nudged = true;
|
||||
}
|
||||
if y == -1 {
|
||||
points[offset + 1] = 0.0f;
|
||||
nudged = true;
|
||||
} else if y == height {
|
||||
points[offset + 1] = height - 1.0;
|
||||
nudged = true;
|
||||
}
|
||||
}
|
||||
offset -= 2;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
301
port_src/output/zxing/common/hybrid_binarizer.rs
Normal file
301
port_src/output/zxing/common/hybrid_binarizer.rs
Normal file
@@ -0,0 +1,301 @@
|
||||
/*
|
||||
* 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::common;
|
||||
|
||||
/**
|
||||
* This class implements a local thresholding algorithm, which while slower than the
|
||||
* GlobalHistogramBinarizer, is fairly efficient for what it does. It is designed for
|
||||
* high frequency images of barcodes with black data on white backgrounds. For this application,
|
||||
* it does a much better job than a global blackpoint with severe shadows and gradients.
|
||||
* However it tends to produce artifacts on lower frequency images and is therefore not
|
||||
* a good general purpose binarizer for uses outside ZXing.
|
||||
*
|
||||
* This class extends GlobalHistogramBinarizer, using the older histogram approach for 1D readers,
|
||||
* and the newer local approach for 2D readers. 1D decoding using a per-row histogram is already
|
||||
* inherently local, and only fails for horizontal gradients. We can revisit that problem later,
|
||||
* but for now it was not a win to use local blocks for 1D.
|
||||
*
|
||||
* This Binarizer is the default for the unit tests and the recommended class for library users.
|
||||
*
|
||||
* @author dswitkin@google.com (Daniel Switkin)
|
||||
*/
|
||||
|
||||
// This class uses 5x5 blocks to compute local luminance, where each block is 8x8 pixels.
|
||||
// So this is the smallest dimension in each axis we can accept.
|
||||
const BLOCK_SIZE_POWER: i32 = 3;
|
||||
|
||||
// ...0100...00
|
||||
const BLOCK_SIZE: i32 = 1 << BLOCK_SIZE_POWER;
|
||||
|
||||
// ...0011...11
|
||||
const BLOCK_SIZE_MASK: i32 = BLOCK_SIZE - 1;
|
||||
|
||||
const MINIMUM_DIMENSION: i32 = BLOCK_SIZE * 5;
|
||||
|
||||
const MIN_DYNAMIC_RANGE: i32 = 24;
|
||||
pub struct HybridBinarizer {
|
||||
super: GlobalHistogramBinarizer;
|
||||
|
||||
let mut matrix: BitMatrix;
|
||||
}
|
||||
|
||||
impl HybridBinarizer {
|
||||
|
||||
pub fn new( source: &LuminanceSource) -> HybridBinarizer {
|
||||
super(source);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the final BitMatrix once for all requests. This could be called once from the
|
||||
* constructor instead, but there are some advantages to doing it lazily, such as making
|
||||
* profiling easier, and not doing heavy lifting when callers don't expect it.
|
||||
*/
|
||||
pub fn get_black_matrix(&self) -> /* throws NotFoundException */Result<BitMatrix, Rc<Exception>> {
|
||||
if self.matrix != null {
|
||||
return Ok(self.matrix);
|
||||
}
|
||||
let source: LuminanceSource = get_luminance_source();
|
||||
let width: i32 = source.get_width();
|
||||
let height: i32 = source.get_height();
|
||||
if width >= MINIMUM_DIMENSION && height >= MINIMUM_DIMENSION {
|
||||
let luminances: Vec<i8> = source.get_matrix();
|
||||
let sub_width: i32 = width >> BLOCK_SIZE_POWER;
|
||||
if (width & BLOCK_SIZE_MASK) != 0 {
|
||||
sub_width += 1;
|
||||
}
|
||||
let sub_height: i32 = height >> BLOCK_SIZE_POWER;
|
||||
if (height & BLOCK_SIZE_MASK) != 0 {
|
||||
sub_height += 1;
|
||||
}
|
||||
let black_points: Vec<Vec<i32>> = ::calculate_black_points(&luminances, sub_width, sub_height, width, height);
|
||||
let new_matrix: BitMatrix = BitMatrix::new(width, height);
|
||||
::calculate_threshold_for_block(&luminances, sub_width, sub_height, width, height, &black_points, new_matrix);
|
||||
self.matrix = new_matrix;
|
||||
} else {
|
||||
// If the image is too small, fall back to the global histogram approach.
|
||||
self.matrix = super.get_black_matrix();
|
||||
}
|
||||
return Ok(self.matrix);
|
||||
}
|
||||
|
||||
pub fn create_binarizer(&self, source: &LuminanceSource) -> Binarizer {
|
||||
return HybridBinarizer::new(source);
|
||||
}
|
||||
|
||||
/**
|
||||
* For each block in the image, calculate the average black point using a 5x5 grid
|
||||
* of the blocks around it. Also handles the corner cases (fractional blocks are computed based
|
||||
* on the last pixels in the row/column which are also used in the previous block).
|
||||
*/
|
||||
fn calculate_threshold_for_block( luminances: &Vec<i8>, sub_width: i32, sub_height: i32, width: i32, height: i32, black_points: &Vec<Vec<i32>>, matrix: &BitMatrix) {
|
||||
let max_y_offset: i32 = height - BLOCK_SIZE;
|
||||
let max_x_offset: i32 = width - BLOCK_SIZE;
|
||||
{
|
||||
let mut y: i32 = 0;
|
||||
while y < sub_height {
|
||||
{
|
||||
let mut yoffset: i32 = y << BLOCK_SIZE_POWER;
|
||||
if yoffset > max_y_offset {
|
||||
yoffset = max_y_offset;
|
||||
}
|
||||
let top: i32 = ::cap(y, sub_height - 3);
|
||||
{
|
||||
let mut x: i32 = 0;
|
||||
while x < sub_width {
|
||||
{
|
||||
let mut xoffset: i32 = x << BLOCK_SIZE_POWER;
|
||||
if xoffset > max_x_offset {
|
||||
xoffset = max_x_offset;
|
||||
}
|
||||
let left: i32 = ::cap(x, sub_width - 3);
|
||||
let mut sum: i32 = 0;
|
||||
{
|
||||
let mut z: i32 = -2;
|
||||
while z <= 2 {
|
||||
{
|
||||
let black_row: Vec<i32> = black_points[top + z];
|
||||
sum += black_row[left - 2] + black_row[left - 1] + black_row[left] + black_row[left + 1] + black_row[left + 2];
|
||||
}
|
||||
z += 1;
|
||||
}
|
||||
}
|
||||
|
||||
let average: i32 = sum / 25;
|
||||
::threshold_block(&luminances, xoffset, yoffset, average, width, matrix);
|
||||
}
|
||||
x += 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
y += 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fn cap( value: i32, max: i32) -> i32 {
|
||||
return if value < 2 { 2 } else { Math::min(value, max) };
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies a single threshold to a block of pixels.
|
||||
*/
|
||||
fn threshold_block( luminances: &Vec<i8>, xoffset: i32, yoffset: i32, threshold: i32, stride: i32, matrix: &BitMatrix) {
|
||||
{
|
||||
let mut y: i32 = 0, let mut offset: i32 = yoffset * stride + xoffset;
|
||||
while y < BLOCK_SIZE {
|
||||
{
|
||||
{
|
||||
let mut x: i32 = 0;
|
||||
while x < BLOCK_SIZE {
|
||||
{
|
||||
// Comparison needs to be <= so that black == 0 pixels are black even if the threshold is 0.
|
||||
if (luminances[offset + x] & 0xFF) <= threshold {
|
||||
matrix.set(xoffset + x, yoffset + y);
|
||||
}
|
||||
}
|
||||
x += 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
y += 1;
|
||||
offset += stride;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates a single black point for each block of pixels and saves it away.
|
||||
* See the following thread for a discussion of this algorithm:
|
||||
* http://groups.google.com/group/zxing/browse_thread/thread/d06efa2c35a7ddc0
|
||||
*/
|
||||
fn calculate_black_points( luminances: &Vec<i8>, sub_width: i32, sub_height: i32, width: i32, height: i32) -> Vec<Vec<i32>> {
|
||||
let max_y_offset: i32 = height - BLOCK_SIZE;
|
||||
let max_x_offset: i32 = width - BLOCK_SIZE;
|
||||
let black_points: [[i32; sub_width]; sub_height] = [[0; sub_width]; sub_height];
|
||||
{
|
||||
let mut y: i32 = 0;
|
||||
while y < sub_height {
|
||||
{
|
||||
let mut yoffset: i32 = y << BLOCK_SIZE_POWER;
|
||||
if yoffset > max_y_offset {
|
||||
yoffset = max_y_offset;
|
||||
}
|
||||
{
|
||||
let mut x: i32 = 0;
|
||||
while x < sub_width {
|
||||
{
|
||||
let mut xoffset: i32 = x << BLOCK_SIZE_POWER;
|
||||
if xoffset > max_x_offset {
|
||||
xoffset = max_x_offset;
|
||||
}
|
||||
let mut sum: i32 = 0;
|
||||
let mut min: i32 = 0xFF;
|
||||
let mut max: i32 = 0;
|
||||
{
|
||||
let mut yy: i32 = 0, let mut offset: i32 = yoffset * width + xoffset;
|
||||
while yy < BLOCK_SIZE {
|
||||
{
|
||||
{
|
||||
let mut xx: i32 = 0;
|
||||
while xx < BLOCK_SIZE {
|
||||
{
|
||||
let pixel: i32 = luminances[offset + xx] & 0xFF;
|
||||
sum += pixel;
|
||||
// still looking for good contrast
|
||||
if pixel < min {
|
||||
min = pixel;
|
||||
}
|
||||
if pixel > max {
|
||||
max = pixel;
|
||||
}
|
||||
}
|
||||
xx += 1;
|
||||
}
|
||||
}
|
||||
|
||||
// short-circuit min/max tests once dynamic range is met
|
||||
if max - min > MIN_DYNAMIC_RANGE {
|
||||
// finish the rest of the rows quickly
|
||||
{
|
||||
yy += 1;
|
||||
offset += width;
|
||||
while yy < BLOCK_SIZE {
|
||||
{
|
||||
{
|
||||
let mut xx: i32 = 0;
|
||||
while xx < BLOCK_SIZE {
|
||||
{
|
||||
sum += luminances[offset + xx] & 0xFF;
|
||||
}
|
||||
xx += 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
yy += 1;
|
||||
offset += width;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
yy += 1;
|
||||
offset += width;
|
||||
}
|
||||
}
|
||||
|
||||
// The default estimate is the average of the values in the block.
|
||||
let mut average: i32 = sum >> (BLOCK_SIZE_POWER * 2);
|
||||
if max - min <= MIN_DYNAMIC_RANGE {
|
||||
// If variation within the block is low, assume this is a block with only light or only
|
||||
// dark pixels. In that case we do not want to use the average, as it would divide this
|
||||
// low contrast area into black and white pixels, essentially creating data out of noise.
|
||||
//
|
||||
// The default assumption is that the block is light/background. Since no estimate for
|
||||
// the level of dark pixels exists locally, use half the min for the block.
|
||||
average = min / 2;
|
||||
if y > 0 && x > 0 {
|
||||
// Correct the "white background" assumption for blocks that have neighbors by comparing
|
||||
// the pixels in this block to the previously calculated black points. This is based on
|
||||
// the fact that dark barcode symbology is always surrounded by some amount of light
|
||||
// background for which reasonable black point estimates were made. The bp estimated at
|
||||
// the boundaries is used for the interior.
|
||||
// The (min < bp) is arbitrary but works better than other heuristics that were tried.
|
||||
let average_neighbor_black_point: i32 = (black_points[y - 1][x] + (2 * black_points[y][x - 1]) + black_points[y - 1][x - 1]) / 4;
|
||||
if min < average_neighbor_black_point {
|
||||
average = average_neighbor_black_point;
|
||||
}
|
||||
}
|
||||
}
|
||||
black_points[y][x] = average;
|
||||
}
|
||||
x += 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
y += 1;
|
||||
}
|
||||
}
|
||||
|
||||
return black_points;
|
||||
}
|
||||
}
|
||||
|
||||
422
port_src/output/zxing/common/minimal_e_c_i_input.rs
Normal file
422
port_src/output/zxing/common/minimal_e_c_i_input.rs
Normal file
@@ -0,0 +1,422 @@
|
||||
/*
|
||||
* Copyright 2021 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::common;
|
||||
|
||||
/**
|
||||
* Class that converts a character string into a sequence of ECIs and bytes
|
||||
*
|
||||
* The implementation uses the Dijkstra algorithm to produce minimal encodings
|
||||
*
|
||||
* @author Alex Geller
|
||||
*/
|
||||
|
||||
// approximated (latch + 2 codewords)
|
||||
const COST_PER_ECI: i32 = 3;
|
||||
#[derive(ECIInput)]
|
||||
pub struct MinimalECIInput {
|
||||
|
||||
let mut bytes: Vec<i32>;
|
||||
|
||||
let fnc1: i32;
|
||||
}
|
||||
|
||||
impl MinimalECIInput {
|
||||
|
||||
/**
|
||||
* Constructs a minimal input
|
||||
*
|
||||
* @param stringToEncode the character string to encode
|
||||
* @param priorityCharset The preferred {@link Charset}. When the value of the argument is null, the algorithm
|
||||
* chooses charsets that leads to a minimal representation. Otherwise the algorithm will use the priority
|
||||
* charset to encode any character in the input that can be encoded by it if the charset is among the
|
||||
* supported charsets.
|
||||
* @param fnc1 denotes the character in the input that represents the FNC1 character or -1 if this is not GS1
|
||||
* input.
|
||||
*/
|
||||
pub fn new( string_to_encode: &String, priority_charset: &Charset, fnc1: i32) -> MinimalECIInput {
|
||||
let .fnc1 = fnc1;
|
||||
let encoder_set: ECIEncoderSet = ECIEncoderSet::new(&string_to_encode, &priority_charset, fnc1);
|
||||
if encoder_set.length() == 1 {
|
||||
//optimization for the case when all can be encoded without ECI in ISO-8859-1
|
||||
bytes = : [i32; string_to_encode.length()] = [0; string_to_encode.length()];
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < bytes.len() {
|
||||
{
|
||||
let c: char = string_to_encode.char_at(i);
|
||||
bytes[i] = if c == fnc1 { 1000 } else { c as i32 };
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
bytes = ::encode_minimally(&string_to_encode, encoder_set, fnc1);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_f_n_c1_character(&self) -> i32 {
|
||||
return self.fnc1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the length of this input. The length is the number
|
||||
* of {@code byte}s, FNC1 characters or ECIs in the sequence.
|
||||
*
|
||||
* @return the number of {@code char}s in this sequence
|
||||
*/
|
||||
pub fn length(&self) -> i32 {
|
||||
return self.bytes.len();
|
||||
}
|
||||
|
||||
pub fn have_n_characters(&self, index: i32, n: i32) -> bool {
|
||||
if index + n - 1 >= self.bytes.len() {
|
||||
return false;
|
||||
}
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < n {
|
||||
{
|
||||
if self.is_e_c_i(index + i) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@code byte} value at the specified index. An index ranges from zero
|
||||
* to {@code length() - 1}. The first {@code byte} value of the sequence is at
|
||||
* index zero, the next at index one, and so on, as for array
|
||||
* indexing.
|
||||
*
|
||||
* @param index the index of the {@code byte} value to be returned
|
||||
*
|
||||
* @return the specified {@code byte} value as character or the FNC1 character
|
||||
*
|
||||
* @throws IndexOutOfBoundsException
|
||||
* if the {@code index} argument is negative or not less than
|
||||
* {@code length()}
|
||||
* @throws IllegalArgumentException
|
||||
* if the value at the {@code index} argument is an ECI (@see #isECI)
|
||||
*/
|
||||
pub fn char_at(&self, index: i32) -> char {
|
||||
if index < 0 || index >= self.length() {
|
||||
throw IndexOutOfBoundsException::new(format!("{}", index));
|
||||
}
|
||||
if self.is_e_c_i(index) {
|
||||
throw IllegalArgumentException::new(format!("value at {} is not a character but an ECI", index));
|
||||
}
|
||||
return if self.is_f_n_c1(index) { self.fnc1 as char } else { self.bytes[index] as char };
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@code CharSequence} that is a subsequence of this sequence.
|
||||
* The subsequence starts with the {@code char} value at the specified index and
|
||||
* ends with the {@code char} value at index {@code end - 1}. The length
|
||||
* (in {@code char}s) of the
|
||||
* returned sequence is {@code end - start}, so if {@code start == end}
|
||||
* then an empty sequence is returned.
|
||||
*
|
||||
* @param start the start index, inclusive
|
||||
* @param end the end index, exclusive
|
||||
*
|
||||
* @return the specified subsequence
|
||||
*
|
||||
* @throws IndexOutOfBoundsException
|
||||
* if {@code start} or {@code end} are negative,
|
||||
* if {@code end} is greater than {@code length()},
|
||||
* or if {@code start} is greater than {@code end}
|
||||
* @throws IllegalArgumentException
|
||||
* if a value in the range {@code start}-{@code end} is an ECI (@see #isECI)
|
||||
*/
|
||||
pub fn sub_sequence(&self, start: i32, end: i32) -> CharSequence {
|
||||
if start < 0 || start > end || end > self.length() {
|
||||
throw IndexOutOfBoundsException::new(format!("{}", start));
|
||||
}
|
||||
let result: StringBuilder = StringBuilder::new();
|
||||
{
|
||||
let mut i: i32 = start;
|
||||
while i < end {
|
||||
{
|
||||
if self.is_e_c_i(i) {
|
||||
throw IllegalArgumentException::new(format!("value at {} is not a character but an ECI", i));
|
||||
}
|
||||
result.append(&self.char_at(i));
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if a value is an ECI
|
||||
*
|
||||
* @param index the index of the value
|
||||
*
|
||||
* @return true if the value at position {@code index} is an ECI
|
||||
*
|
||||
* @throws IndexOutOfBoundsException
|
||||
* if the {@code index} argument is negative or not less than
|
||||
* {@code length()}
|
||||
*/
|
||||
pub fn is_e_c_i(&self, index: i32) -> bool {
|
||||
if index < 0 || index >= self.length() {
|
||||
throw IndexOutOfBoundsException::new(format!("{}", index));
|
||||
}
|
||||
return self.bytes[index] > 255 && self.bytes[index] <= 999;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if a value is the FNC1 character
|
||||
*
|
||||
* @param index the index of the value
|
||||
*
|
||||
* @return true if the value at position {@code index} is the FNC1 character
|
||||
*
|
||||
* @throws IndexOutOfBoundsException
|
||||
* if the {@code index} argument is negative or not less than
|
||||
* {@code length()}
|
||||
*/
|
||||
pub fn is_f_n_c1(&self, index: i32) -> bool {
|
||||
if index < 0 || index >= self.length() {
|
||||
throw IndexOutOfBoundsException::new(format!("{}", index));
|
||||
}
|
||||
return self.bytes[index] == 1000;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@code int} ECI value at the specified index. An index ranges from zero
|
||||
* to {@code length() - 1}. The first {@code byte} value of the sequence is at
|
||||
* index zero, the next at index one, and so on, as for array
|
||||
* indexing.
|
||||
*
|
||||
* @param index the index of the {@code int} value to be returned
|
||||
*
|
||||
* @return the specified {@code int} ECI value.
|
||||
* The ECI specified the encoding of all bytes with a higher index until the
|
||||
* next ECI or until the end of the input if no other ECI follows.
|
||||
*
|
||||
* @throws IndexOutOfBoundsException
|
||||
* if the {@code index} argument is negative or not less than
|
||||
* {@code length()}
|
||||
* @throws IllegalArgumentException
|
||||
* if the value at the {@code index} argument is not an ECI (@see #isECI)
|
||||
*/
|
||||
pub fn get_e_c_i_value(&self, index: i32) -> i32 {
|
||||
if index < 0 || index >= self.length() {
|
||||
throw IndexOutOfBoundsException::new(format!("{}", index));
|
||||
}
|
||||
if !self.is_e_c_i(index) {
|
||||
throw IllegalArgumentException::new(format!("value at {} is not an ECI but a character", index));
|
||||
}
|
||||
return self.bytes[index] - 256;
|
||||
}
|
||||
|
||||
pub fn to_string(&self) -> String {
|
||||
let result: StringBuilder = StringBuilder::new();
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < self.length() {
|
||||
{
|
||||
if i > 0 {
|
||||
result.append(", ");
|
||||
}
|
||||
if self.is_e_c_i(i) {
|
||||
result.append("ECI(");
|
||||
result.append(&self.get_e_c_i_value(i));
|
||||
result.append(')');
|
||||
} else if self.char_at(i) < 128 {
|
||||
result.append('\'');
|
||||
result.append(&self.char_at(i));
|
||||
result.append('\'');
|
||||
} else {
|
||||
result.append(self.char_at(i) as i32);
|
||||
}
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
return result.to_string();
|
||||
}
|
||||
|
||||
fn add_edge( edges: &Vec<Vec<InputEdge>>, to: i32, edge: &InputEdge) {
|
||||
if edges[to][edge.encoderIndex] == null || edges[to][edge.encoderIndex].cachedTotalSize > edge.cachedTotalSize {
|
||||
edges[to][edge.encoderIndex] = edge;
|
||||
}
|
||||
}
|
||||
|
||||
fn add_edges( string_to_encode: &String, encoder_set: &ECIEncoderSet, edges: &Vec<Vec<InputEdge>>, from: i32, previous: &InputEdge, fnc1: i32) {
|
||||
let ch: char = string_to_encode.char_at(from);
|
||||
let mut start: i32 = 0;
|
||||
let mut end: i32 = encoder_set.length();
|
||||
if encoder_set.get_priority_encoder_index() >= 0 && (ch == fnc1 || encoder_set.can_encode(ch, &encoder_set.get_priority_encoder_index())) {
|
||||
start = encoder_set.get_priority_encoder_index();
|
||||
end = start + 1;
|
||||
}
|
||||
{
|
||||
let mut i: i32 = start;
|
||||
while i < end {
|
||||
{
|
||||
if ch == fnc1 || encoder_set.can_encode(ch, i) {
|
||||
::add_edge(edges, from + 1, InputEdge::new(ch, encoder_set, i, previous, fnc1));
|
||||
}
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fn encode_minimally( string_to_encode: &String, encoder_set: &ECIEncoderSet, fnc1: i32) -> Vec<i32> {
|
||||
let input_length: i32 = string_to_encode.length();
|
||||
// Array that represents vertices. There is a vertex for every character and encoding.
|
||||
let mut edges: [[Option<InputEdge>; encoder_set.length()]; input_length + 1] = [[None; encoder_set.length()]; input_length + 1];
|
||||
::add_edges(&string_to_encode, encoder_set, edges, 0, null, fnc1);
|
||||
{
|
||||
let mut i: i32 = 1;
|
||||
while i <= input_length {
|
||||
{
|
||||
{
|
||||
let mut j: i32 = 0;
|
||||
while j < encoder_set.length() {
|
||||
{
|
||||
if edges[i][j] != null && i < input_length {
|
||||
::add_edges(&string_to_encode, encoder_set, edges, i, edges[i][j], fnc1);
|
||||
}
|
||||
}
|
||||
j += 1;
|
||||
}
|
||||
}
|
||||
|
||||
//optimize memory by removing edges that have been passed.
|
||||
{
|
||||
let mut j: i32 = 0;
|
||||
while j < encoder_set.length() {
|
||||
{
|
||||
edges[i - 1][j] = null;
|
||||
}
|
||||
j += 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
let minimal_j: i32 = -1;
|
||||
let minimal_size: i32 = Integer::MAX_VALUE;
|
||||
{
|
||||
let mut j: i32 = 0;
|
||||
while j < encoder_set.length() {
|
||||
{
|
||||
if edges[input_length][j] != null {
|
||||
let edge: InputEdge = edges[input_length][j];
|
||||
if edge.cachedTotalSize < minimal_size {
|
||||
minimal_size = edge.cachedTotalSize;
|
||||
minimal_j = j;
|
||||
}
|
||||
}
|
||||
}
|
||||
j += 1;
|
||||
}
|
||||
}
|
||||
|
||||
if minimal_j < 0 {
|
||||
throw RuntimeException::new(format!("Internal error: failed to encode \"{}\"", string_to_encode));
|
||||
}
|
||||
let ints_a_l: List<Integer> = ArrayList<>::new();
|
||||
let mut current: InputEdge = edges[input_length][minimal_j];
|
||||
while current != null {
|
||||
if current.is_f_n_c1() {
|
||||
ints_a_l.add(0, 1000);
|
||||
} else {
|
||||
let bytes: Vec<i8> = encoder_set.encode(current.c, current.encoderIndex);
|
||||
{
|
||||
let mut i: i32 = bytes.len() - 1;
|
||||
while i >= 0 {
|
||||
{
|
||||
ints_a_l.add(0, (bytes[i] & 0xFF));
|
||||
}
|
||||
i -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
let previous_encoder_index: i32 = if current.previous == null { 0 } else { current.previous.encoderIndex };
|
||||
if previous_encoder_index != current.encoderIndex {
|
||||
ints_a_l.add(0, 256 + encoder_set.get_e_c_i_value(current.encoderIndex));
|
||||
}
|
||||
current = current.previous;
|
||||
}
|
||||
let mut ints: [i32; ints_a_l.size()] = [0; ints_a_l.size()];
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < ints.len() {
|
||||
{
|
||||
ints[i] = ints_a_l.get(i);
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
return ints;
|
||||
}
|
||||
|
||||
struct InputEdge {
|
||||
|
||||
let c: char;
|
||||
|
||||
//the encoding of this edge
|
||||
let encoder_index: i32;
|
||||
|
||||
let previous: InputEdge;
|
||||
|
||||
let cached_total_size: i32;
|
||||
}
|
||||
|
||||
impl InputEdge {
|
||||
|
||||
fn new( c: char, encoder_set: &ECIEncoderSet, encoder_index: i32, previous: &InputEdge, fnc1: i32) -> InputEdge {
|
||||
let .c = if c == fnc1 { 1000 } else { c };
|
||||
let .encoderIndex = encoder_index;
|
||||
let .previous = previous;
|
||||
let mut size: i32 = if let .c == 1000 { 1 } else { encoder_set.encode(c, encoder_index).len() };
|
||||
let previous_encoder_index: i32 = if previous == null { 0 } else { previous.encoderIndex };
|
||||
if previous_encoder_index != encoder_index {
|
||||
size += COST_PER_ECI;
|
||||
}
|
||||
if previous != null {
|
||||
size += previous.cachedTotalSize;
|
||||
}
|
||||
let .cachedTotalSize = size;
|
||||
}
|
||||
|
||||
fn is_f_n_c1(&self) -> bool {
|
||||
return self.c == 1000;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
144
port_src/output/zxing/common/perspective_transform.rs
Normal file
144
port_src/output/zxing/common/perspective_transform.rs
Normal file
@@ -0,0 +1,144 @@
|
||||
/*
|
||||
* 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::common;
|
||||
|
||||
/**
|
||||
* <p>This class implements a perspective transform in two dimensions. Given four source and four
|
||||
* destination points, it will compute the transformation implied between them. The code is based
|
||||
* directly upon section 3.4.2 of George Wolberg's "Digital Image Warping"; see pages 54-56.</p>
|
||||
*
|
||||
* @author Sean Owen
|
||||
*/
|
||||
pub struct PerspectiveTransform {
|
||||
|
||||
let a11: f32;
|
||||
|
||||
let a12: f32;
|
||||
|
||||
let a13: f32;
|
||||
|
||||
let a21: f32;
|
||||
|
||||
let a22: f32;
|
||||
|
||||
let a23: f32;
|
||||
|
||||
let a31: f32;
|
||||
|
||||
let a32: f32;
|
||||
|
||||
let a33: f32;
|
||||
}
|
||||
|
||||
impl PerspectiveTransform {
|
||||
|
||||
fn new( a11: f32, a21: f32, a31: f32, a12: f32, a22: f32, a32: f32, a13: f32, a23: f32, a33: f32) -> PerspectiveTransform {
|
||||
let .a11 = a11;
|
||||
let .a12 = a12;
|
||||
let .a13 = a13;
|
||||
let .a21 = a21;
|
||||
let .a22 = a22;
|
||||
let .a23 = a23;
|
||||
let .a31 = a31;
|
||||
let .a32 = a32;
|
||||
let .a33 = a33;
|
||||
}
|
||||
|
||||
pub fn quadrilateral_to_quadrilateral( x0: f32, y0: f32, x1: f32, y1: f32, x2: f32, y2: f32, x3: f32, y3: f32, x0p: f32, y0p: f32, x1p: f32, y1p: f32, x2p: f32, y2p: f32, x3p: f32, y3p: f32) -> PerspectiveTransform {
|
||||
let q_to_s: PerspectiveTransform = ::quadrilateral_to_square(x0, y0, x1, y1, x2, y2, x3, y3);
|
||||
let s_to_q: PerspectiveTransform = ::square_to_quadrilateral(x0p, y0p, x1p, y1p, x2p, y2p, x3p, y3p);
|
||||
return s_to_q.times(q_to_s);
|
||||
}
|
||||
|
||||
pub fn transform_points(&self, points: &Vec<f32>) {
|
||||
let a11: f32 = self.a11;
|
||||
let a12: f32 = self.a12;
|
||||
let a13: f32 = self.a13;
|
||||
let a21: f32 = self.a21;
|
||||
let a22: f32 = self.a22;
|
||||
let a23: f32 = self.a23;
|
||||
let a31: f32 = self.a31;
|
||||
let a32: f32 = self.a32;
|
||||
let a33: f32 = self.a33;
|
||||
// points.length must be even
|
||||
let max_i: i32 = points.len() - 1;
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < max_i {
|
||||
{
|
||||
let x: f32 = points[i];
|
||||
let y: f32 = points[i + 1];
|
||||
let denominator: f32 = a13 * x + a23 * y + a33;
|
||||
points[i] = (a11 * x + a21 * y + a31) / denominator;
|
||||
points[i + 1] = (a12 * x + a22 * y + a32) / denominator;
|
||||
}
|
||||
i += 2;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
pub fn transform_points(&self, x_values: &Vec<f32>, y_values: &Vec<f32>) {
|
||||
let n: i32 = x_values.len();
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < n {
|
||||
{
|
||||
let x: f32 = x_values[i];
|
||||
let y: f32 = y_values[i];
|
||||
let denominator: f32 = self.a13 * x + self.a23 * y + self.a33;
|
||||
x_values[i] = (self.a11 * x + self.a21 * y + self.a31) / denominator;
|
||||
y_values[i] = (self.a12 * x + self.a22 * y + self.a32) / denominator;
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
pub fn square_to_quadrilateral( x0: f32, y0: f32, x1: f32, y1: f32, x2: f32, y2: f32, x3: f32, y3: f32) -> PerspectiveTransform {
|
||||
let dx3: f32 = x0 - x1 + x2 - x3;
|
||||
let dy3: f32 = y0 - y1 + y2 - y3;
|
||||
if dx3 == 0.0f && dy3 == 0.0f {
|
||||
// Affine
|
||||
return PerspectiveTransform::new(x1 - x0, x2 - x1, x0, y1 - y0, y2 - y1, y0, 0.0f, 0.0f, 1.0f);
|
||||
} else {
|
||||
let dx1: f32 = x1 - x2;
|
||||
let dx2: f32 = x3 - x2;
|
||||
let dy1: f32 = y1 - y2;
|
||||
let dy2: f32 = y3 - y2;
|
||||
let denominator: f32 = dx1 * dy2 - dx2 * dy1;
|
||||
let a13: f32 = (dx3 * dy2 - dx2 * dy3) / denominator;
|
||||
let a23: f32 = (dx1 * dy3 - dx3 * dy1) / denominator;
|
||||
return PerspectiveTransform::new(x1 - x0 + a13 * x1, x3 - x0 + a23 * x3, x0, y1 - y0 + a13 * y1, y3 - y0 + a23 * y3, y0, a13, a23, 1.0f);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn quadrilateral_to_square( x0: f32, y0: f32, x1: f32, y1: f32, x2: f32, y2: f32, x3: f32, y3: f32) -> PerspectiveTransform {
|
||||
// Here, the adjoint serves as the inverse:
|
||||
return ::square_to_quadrilateral(x0, y0, x1, y1, x2, y2, x3, y3).build_adjoint();
|
||||
}
|
||||
|
||||
fn build_adjoint(&self) -> PerspectiveTransform {
|
||||
// Adjoint is the transpose of the cofactor matrix:
|
||||
return PerspectiveTransform::new(self.a22 * self.a33 - self.a23 * self.a32, self.a23 * self.a31 - self.a21 * self.a33, self.a21 * self.a32 - self.a22 * self.a31, self.a13 * self.a32 - self.a12 * self.a33, self.a11 * self.a33 - self.a13 * self.a31, self.a12 * self.a31 - self.a11 * self.a32, self.a12 * self.a23 - self.a13 * self.a22, self.a13 * self.a21 - self.a11 * self.a23, self.a11 * self.a22 - self.a12 * self.a21);
|
||||
}
|
||||
|
||||
fn times(&self, other: &PerspectiveTransform) -> PerspectiveTransform {
|
||||
return PerspectiveTransform::new(self.a11 * other.a11 + self.a21 * other.a12 + self.a31 * other.a13, self.a11 * other.a21 + self.a21 * other.a22 + self.a31 * other.a23, self.a11 * other.a31 + self.a21 * other.a32 + self.a31 * other.a33, self.a12 * other.a11 + self.a22 * other.a12 + self.a32 * other.a13, self.a12 * other.a21 + self.a22 * other.a22 + self.a32 * other.a23, self.a12 * other.a31 + self.a22 * other.a32 + self.a32 * other.a33, self.a13 * other.a11 + self.a23 * other.a12 + self.a33 * other.a13, self.a13 * other.a21 + self.a23 * other.a22 + self.a33 * other.a23, self.a13 * other.a31 + self.a23 * other.a32 + self.a33 * other.a33);
|
||||
}
|
||||
}
|
||||
|
||||
202
port_src/output/zxing/common/reedsolomon/generic_g_f.rs
Normal file
202
port_src/output/zxing/common/reedsolomon/generic_g_f.rs
Normal file
@@ -0,0 +1,202 @@
|
||||
/*
|
||||
* 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::common::reedsolomon;
|
||||
|
||||
/**
|
||||
* <p>This class contains utility methods for performing mathematical operations over
|
||||
* the Galois Fields. Operations use a given primitive polynomial in calculations.</p>
|
||||
*
|
||||
* <p>Throughout this package, elements of the GF are represented as an {@code int}
|
||||
* for convenience and speed (but at the cost of memory).
|
||||
* </p>
|
||||
*
|
||||
* @author Sean Owen
|
||||
* @author David Olivier
|
||||
*/
|
||||
|
||||
// x^12 + x^6 + x^5 + x^3 + 1
|
||||
const AZTEC_DATA_12: GenericGF = GenericGF::new(0x1069, 4096, 1);
|
||||
|
||||
// x^10 + x^3 + 1
|
||||
const AZTEC_DATA_10: GenericGF = GenericGF::new(0x409, 1024, 1);
|
||||
|
||||
// x^6 + x + 1
|
||||
const AZTEC_DATA_6: GenericGF = GenericGF::new(0x43, 64, 1);
|
||||
|
||||
// x^4 + x + 1
|
||||
const AZTEC_PARAM: GenericGF = GenericGF::new(0x13, 16, 1);
|
||||
|
||||
// x^8 + x^4 + x^3 + x^2 + 1
|
||||
const QR_CODE_FIELD_256: GenericGF = GenericGF::new(0x011D, 256, 0);
|
||||
|
||||
// x^8 + x^5 + x^3 + x^2 + 1
|
||||
const DATA_MATRIX_FIELD_256: GenericGF = GenericGF::new(0x012D, 256, 1);
|
||||
|
||||
const AZTEC_DATA_8: GenericGF = DATA_MATRIX_FIELD_256;
|
||||
|
||||
const MAXICODE_FIELD_64: GenericGF = AZTEC_DATA_6;
|
||||
pub struct GenericGF {
|
||||
|
||||
let exp_table: Vec<i32>;
|
||||
|
||||
let log_table: Vec<i32>;
|
||||
|
||||
let mut zero: GenericGFPoly;
|
||||
|
||||
let mut one: GenericGFPoly;
|
||||
|
||||
let size: i32;
|
||||
|
||||
let primitive: i32;
|
||||
|
||||
let generator_base: i32;
|
||||
}
|
||||
|
||||
impl GenericGF {
|
||||
|
||||
/**
|
||||
* Create a representation of GF(size) using the given primitive polynomial.
|
||||
*
|
||||
* @param primitive irreducible polynomial whose coefficients are represented by
|
||||
* the bits of an int, where the least-significant bit represents the constant
|
||||
* coefficient
|
||||
* @param size the size of the field
|
||||
* @param b the factor b in the generator polynomial can be 0- or 1-based
|
||||
* (g(x) = (x+a^b)(x+a^(b+1))...(x+a^(b+2t-1))).
|
||||
* In most cases it should be 1, but for QR code it is 0.
|
||||
*/
|
||||
pub fn new( primitive: i32, size: i32, b: i32) -> GenericGF {
|
||||
let .primitive = primitive;
|
||||
let .size = size;
|
||||
let .generatorBase = b;
|
||||
exp_table = : [i32; size] = [0; size];
|
||||
log_table = : [i32; size] = [0; size];
|
||||
let mut x: i32 = 1;
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < size {
|
||||
{
|
||||
exp_table[i] = x;
|
||||
// we're assuming the generator alpha is 2
|
||||
x *= 2;
|
||||
if x >= size {
|
||||
x ^= primitive;
|
||||
x &= size - 1;
|
||||
}
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < size - 1 {
|
||||
{
|
||||
log_table[exp_table[i]] = i;
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
// logTable[0] == 0 but this should never be used
|
||||
zero = GenericGFPoly::new(let , : vec![i32; 1] = vec![0, ]
|
||||
);
|
||||
one = GenericGFPoly::new(let , : vec![i32; 1] = vec![1, ]
|
||||
);
|
||||
}
|
||||
|
||||
fn get_zero(&self) -> GenericGFPoly {
|
||||
return self.zero;
|
||||
}
|
||||
|
||||
fn get_one(&self) -> GenericGFPoly {
|
||||
return self.one;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the monomial representing coefficient * x^degree
|
||||
*/
|
||||
fn build_monomial(&self, degree: i32, coefficient: i32) -> GenericGFPoly {
|
||||
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 GenericGFPoly::new(self, &coefficients);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements both addition and subtraction -- they are the same in GF(size).
|
||||
*
|
||||
* @return sum/difference of a and b
|
||||
*/
|
||||
fn add_or_subtract( a: i32, b: i32) -> i32 {
|
||||
return a ^ b;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return 2 to the power of a in GF(size)
|
||||
*/
|
||||
fn exp(&self, a: i32) -> i32 {
|
||||
return self.exp_table[a];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return base 2 log of a in GF(size)
|
||||
*/
|
||||
fn log(&self, a: i32) -> i32 {
|
||||
if a == 0 {
|
||||
throw IllegalArgumentException::new();
|
||||
}
|
||||
return self.log_table[a];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return multiplicative inverse of a
|
||||
*/
|
||||
fn inverse(&self, a: i32) -> i32 {
|
||||
if a == 0 {
|
||||
throw ArithmeticException::new();
|
||||
}
|
||||
return self.exp_table[self.size - self.log_table[a] - 1];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return product of a and b in GF(size)
|
||||
*/
|
||||
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.size - 1)];
|
||||
}
|
||||
|
||||
pub fn get_size(&self) -> i32 {
|
||||
return self.size;
|
||||
}
|
||||
|
||||
pub fn get_generator_base(&self) -> i32 {
|
||||
return self.generator_base;
|
||||
}
|
||||
|
||||
pub fn to_string(&self) -> String {
|
||||
return format!("GF(0x{},{})", Integer::to_hex_string(self.primitive), self.size);
|
||||
}
|
||||
}
|
||||
|
||||
312
port_src/output/zxing/common/reedsolomon/generic_g_f_poly.rs
Normal file
312
port_src/output/zxing/common/reedsolomon/generic_g_f_poly.rs
Normal file
@@ -0,0 +1,312 @@
|
||||
/*
|
||||
* 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::common::reedsolomon;
|
||||
|
||||
/**
|
||||
* <p>Represents a polynomial whose coefficients are elements of a GF.
|
||||
* Instances of this class are immutable.</p>
|
||||
*
|
||||
* <p>Much credit is due to William Rucklidge since portions of this code are an indirect
|
||||
* port of his C++ Reed-Solomon implementation.</p>
|
||||
*
|
||||
* @author Sean Owen
|
||||
*/
|
||||
struct GenericGFPoly {
|
||||
|
||||
let field: GenericGF;
|
||||
|
||||
let coefficients: Vec<i32>;
|
||||
}
|
||||
|
||||
impl GenericGFPoly {
|
||||
|
||||
/**
|
||||
* @param field the {@link GenericGF} instance representing the field to use
|
||||
* to perform computations
|
||||
* @param coefficients coefficients as ints representing elements of GF(size), arranged
|
||||
* from most significant (highest-power term) coefficient to least significant
|
||||
* @throws IllegalArgumentException if argument is null or empty,
|
||||
* or if leading coefficient is 0 and this is not a
|
||||
* constant polynomial (that is, it is not the monomial "0")
|
||||
*/
|
||||
fn new( field: &GenericGF, coefficients: &Vec<i32>) -> GenericGFPoly {
|
||||
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 = GenericGF::add_or_subtract(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 = GenericGF::add_or_subtract(&self.field.multiply(a, result), self.coefficients[i]);
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
fn add_or_subtract(&self, other: &GenericGFPoly) -> GenericGFPoly {
|
||||
if !self.field.equals(other.field) {
|
||||
throw IllegalArgumentException::new("GenericGFPolys do not have same GenericGF 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] = GenericGF::add_or_subtract(smaller_coefficients[i - length_diff], larger_coefficients[i]);
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
return GenericGFPoly::new(self.field, &sum_diff);
|
||||
}
|
||||
|
||||
fn multiply(&self, other: &GenericGFPoly) -> GenericGFPoly {
|
||||
if !self.field.equals(other.field) {
|
||||
throw IllegalArgumentException::new("GenericGFPolys do not have same GenericGF 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] = GenericGF::add_or_subtract(product[i + j], &self.field.multiply(a_coeff, b_coefficients[j]));
|
||||
}
|
||||
j += 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
return GenericGFPoly::new(self.field, &product);
|
||||
}
|
||||
|
||||
fn multiply(&self, scalar: i32) -> GenericGFPoly {
|
||||
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 GenericGFPoly::new(self.field, &product);
|
||||
}
|
||||
|
||||
fn multiply_by_monomial(&self, degree: i32, coefficient: i32) -> GenericGFPoly {
|
||||
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 GenericGFPoly::new(self.field, &product);
|
||||
}
|
||||
|
||||
fn divide(&self, other: &GenericGFPoly) -> Vec<GenericGFPoly> {
|
||||
if !self.field.equals(other.field) {
|
||||
throw IllegalArgumentException::new("GenericGFPolys do not have same GenericGF field");
|
||||
}
|
||||
if other.is_zero() {
|
||||
throw IllegalArgumentException::new("Divide by 0");
|
||||
}
|
||||
let mut quotient: GenericGFPoly = self.field.get_zero();
|
||||
let mut remainder: GenericGFPoly = self;
|
||||
let denominator_leading_term: i32 = other.get_coefficient(&other.get_degree());
|
||||
let inverse_denominator_leading_term: i32 = self.field.inverse(denominator_leading_term);
|
||||
while remainder.get_degree() >= other.get_degree() && !remainder.is_zero() {
|
||||
let degree_difference: i32 = remainder.get_degree() - other.get_degree();
|
||||
let scale: i32 = self.field.multiply(&remainder.get_coefficient(&remainder.get_degree()), inverse_denominator_leading_term);
|
||||
let term: GenericGFPoly = other.multiply_by_monomial(degree_difference, scale);
|
||||
let iteration_quotient: GenericGFPoly = self.field.build_monomial(degree_difference, scale);
|
||||
quotient = quotient.add_or_subtract(iteration_quotient);
|
||||
remainder = remainder.add_or_subtract(term);
|
||||
}
|
||||
return : vec![GenericGFPoly; 2] = vec![quotient, remainder, ]
|
||||
;
|
||||
}
|
||||
|
||||
pub fn to_string(&self) -> String {
|
||||
if self.is_zero() {
|
||||
return "0";
|
||||
}
|
||||
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 {
|
||||
if degree == self.get_degree() {
|
||||
result.append("-");
|
||||
} else {
|
||||
result.append(" - ");
|
||||
}
|
||||
coefficient = -coefficient;
|
||||
} else {
|
||||
if result.length() > 0 {
|
||||
result.append(" + ");
|
||||
}
|
||||
}
|
||||
if degree == 0 || coefficient != 1 {
|
||||
let alpha_power: i32 = self.field.log(coefficient);
|
||||
if alpha_power == 0 {
|
||||
result.append('1');
|
||||
} else if alpha_power == 1 {
|
||||
result.append('a');
|
||||
} else {
|
||||
result.append("a^");
|
||||
result.append(alpha_power);
|
||||
}
|
||||
}
|
||||
if degree != 0 {
|
||||
if degree == 1 {
|
||||
result.append('x');
|
||||
} else {
|
||||
result.append("x^");
|
||||
result.append(degree);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
degree -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
return result.to_string();
|
||||
}
|
||||
}
|
||||
|
||||
220
port_src/output/zxing/common/reedsolomon/reed_solomon_decoder.rs
Normal file
220
port_src/output/zxing/common/reedsolomon/reed_solomon_decoder.rs
Normal file
@@ -0,0 +1,220 @@
|
||||
/*
|
||||
* 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::common::reedsolomon;
|
||||
|
||||
/**
|
||||
* <p>Implements Reed-Solomon decoding, as the name implies.</p>
|
||||
*
|
||||
* <p>The algorithm will not be explained here, but the following references were helpful
|
||||
* in creating this implementation:</p>
|
||||
*
|
||||
* <ul>
|
||||
* <li>Bruce Maggs.
|
||||
* <a href="http://www.cs.cmu.edu/afs/cs.cmu.edu/project/pscico-guyb/realworld/www/rs_decode.ps">
|
||||
* "Decoding Reed-Solomon Codes"</a> (see discussion of Forney's Formula)</li>
|
||||
* <li>J.I. Hall. <a href="www.mth.msu.edu/~jhall/classes/codenotes/GRS.pdf">
|
||||
* "Chapter 5. Generalized Reed-Solomon Codes"</a>
|
||||
* (see discussion of Euclidean algorithm)</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p>Much credit is due to William Rucklidge since portions of this code are an indirect
|
||||
* port of his C++ Reed-Solomon implementation.</p>
|
||||
*
|
||||
* @author Sean Owen
|
||||
* @author William Rucklidge
|
||||
* @author sanfordsquires
|
||||
*/
|
||||
pub struct ReedSolomonDecoder {
|
||||
|
||||
let field: GenericGF;
|
||||
}
|
||||
|
||||
impl ReedSolomonDecoder {
|
||||
|
||||
pub fn new( field: &GenericGF) -> ReedSolomonDecoder {
|
||||
let .field = field;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Decodes given set of received codewords, which include both data and error-correction
|
||||
* codewords. Really, this means it uses Reed-Solomon to detect and correct errors, in-place,
|
||||
* in the input.</p>
|
||||
*
|
||||
* @param received data and error-correction codewords
|
||||
* @param twoS number of error-correction codewords available
|
||||
* @throws ReedSolomonException if decoding fails for any reason
|
||||
*/
|
||||
pub fn decode(&self, received: &Vec<i32>, two_s: i32) -> /* throws ReedSolomonException */Result<Void, Rc<Exception>> {
|
||||
let poly: GenericGFPoly = GenericGFPoly::new(self.field, &received);
|
||||
let syndrome_coefficients: [i32; two_s] = [0; two_s];
|
||||
let no_error: bool = true;
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < two_s {
|
||||
{
|
||||
let eval: i32 = poly.evaluate_at(&self.field.exp(i + self.field.get_generator_base()));
|
||||
syndrome_coefficients[syndrome_coefficients.len() - 1 - i] = eval;
|
||||
if eval != 0 {
|
||||
no_error = false;
|
||||
}
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
if no_error {
|
||||
return;
|
||||
}
|
||||
let syndrome: GenericGFPoly = GenericGFPoly::new(self.field, &syndrome_coefficients);
|
||||
let sigma_omega: Vec<GenericGFPoly> = self.run_euclidean_algorithm(&self.field.build_monomial(two_s, 1), syndrome, two_s);
|
||||
let sigma: GenericGFPoly = sigma_omega[0];
|
||||
let omega: GenericGFPoly = sigma_omega[1];
|
||||
let error_locations: Vec<i32> = self.find_error_locations(sigma);
|
||||
let error_magnitudes: Vec<i32> = self.find_error_magnitudes(omega, &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 ReedSolomonException::new("Bad error location");
|
||||
}
|
||||
received[position] = GenericGF::add_or_subtract(received[position], error_magnitudes[i]);
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fn run_euclidean_algorithm(&self, a: &GenericGFPoly, b: &GenericGFPoly, R: i32) -> /* throws ReedSolomonException */Result<Vec<GenericGFPoly>, Rc<Exception>> {
|
||||
// Assume a's degree is >= b's
|
||||
if a.get_degree() < b.get_degree() {
|
||||
let temp: GenericGFPoly = a;
|
||||
a = b;
|
||||
b = temp;
|
||||
}
|
||||
let r_last: GenericGFPoly = a;
|
||||
let mut r: GenericGFPoly = b;
|
||||
let t_last: GenericGFPoly = self.field.get_zero();
|
||||
let mut t: GenericGFPoly = self.field.get_one();
|
||||
// Run Euclidean algorithm until r's degree is less than R/2
|
||||
while 2 * r.get_degree() >= R {
|
||||
let r_last_last: GenericGFPoly = r_last;
|
||||
let t_last_last: GenericGFPoly = 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 ReedSolomonException::new("r_{i-1} was zero");
|
||||
}
|
||||
r = r_last_last;
|
||||
let mut q: GenericGFPoly = 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_or_subtract(&self.field.build_monomial(degree_diff, scale));
|
||||
r = r.add_or_subtract(&r_last.multiply_by_monomial(degree_diff, scale));
|
||||
}
|
||||
t = q.multiply(t_last).add_or_subtract(t_last_last);
|
||||
if r.get_degree() >= r_last.get_degree() {
|
||||
throw IllegalStateException::new(format!("Division algorithm failed to reduce polynomial? r: {}, rLast: {}", r, r_last));
|
||||
}
|
||||
}
|
||||
let sigma_tilde_at_zero: i32 = t.get_coefficient(0);
|
||||
if sigma_tilde_at_zero == 0 {
|
||||
throw ReedSolomonException::new("sigmaTilde(0) was zero");
|
||||
}
|
||||
let inverse: i32 = self.field.inverse(sigma_tilde_at_zero);
|
||||
let sigma: GenericGFPoly = t.multiply(inverse);
|
||||
let omega: GenericGFPoly = r.multiply(inverse);
|
||||
return Ok( : vec![GenericGFPoly; 2] = vec![sigma, omega, ]
|
||||
);
|
||||
}
|
||||
|
||||
fn find_error_locations(&self, error_locator: &GenericGFPoly) -> /* throws ReedSolomonException */Result<Vec<i32>, Rc<Exception>> {
|
||||
// This is a direct application of Chien's search
|
||||
let num_errors: i32 = error_locator.get_degree();
|
||||
if num_errors == 1 {
|
||||
// shortcut
|
||||
return Ok( : vec![i32; 1] = vec![error_locator.get_coefficient(1), ]
|
||||
);
|
||||
}
|
||||
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 ReedSolomonException::new("Error locator degree does not match number of roots");
|
||||
}
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
fn find_error_magnitudes(&self, error_evaluator: &GenericGFPoly, error_locations: &Vec<i32>) -> Vec<i32> {
|
||||
// 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 mut denominator: i32 = 1;
|
||||
{
|
||||
let mut j: i32 = 0;
|
||||
while j < s {
|
||||
{
|
||||
if i != j {
|
||||
//denominator = field.multiply(denominator,
|
||||
// GenericGF.addOrSubtract(1, field.multiply(errorLocations[j], xiInverse)));
|
||||
// Above should work but fails on some Apple and Linux JDKs due to a Hotspot bug.
|
||||
// Below is a funny-looking workaround from Steven Parkes
|
||||
let term: i32 = self.field.multiply(error_locations[j], xi_inverse);
|
||||
let term_plus1: i32 = if (term & 0x1) == 0 { term | 1 } else { term & ~1 };
|
||||
denominator = self.field.multiply(denominator, term_plus1);
|
||||
}
|
||||
}
|
||||
j += 1;
|
||||
}
|
||||
}
|
||||
|
||||
result[i] = self.field.multiply(&error_evaluator.evaluate_at(xi_inverse), &self.field.inverse(denominator));
|
||||
if self.field.get_generator_base() != 0 {
|
||||
result[i] = self.field.multiply(result[i], xi_inverse);
|
||||
}
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* 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::common::reedsolomon;
|
||||
|
||||
/**
|
||||
* <p>Implements Reed-Solomon encoding, as the name implies.</p>
|
||||
*
|
||||
* @author Sean Owen
|
||||
* @author William Rucklidge
|
||||
*/
|
||||
pub struct ReedSolomonEncoder {
|
||||
|
||||
let field: GenericGF;
|
||||
|
||||
let cached_generators: List<GenericGFPoly>;
|
||||
}
|
||||
|
||||
impl ReedSolomonEncoder {
|
||||
|
||||
pub fn new( field: &GenericGF) -> ReedSolomonEncoder {
|
||||
let .field = field;
|
||||
let .cachedGenerators = ArrayList<>::new();
|
||||
cached_generators.add(GenericGFPoly::new(field, : vec![i32; 1] = vec![1, ]
|
||||
));
|
||||
}
|
||||
|
||||
fn build_generator(&self, degree: i32) -> GenericGFPoly {
|
||||
if degree >= self.cached_generators.size() {
|
||||
let last_generator: GenericGFPoly = self.cached_generators.get(self.cached_generators.size() - 1);
|
||||
{
|
||||
let mut d: i32 = self.cached_generators.size();
|
||||
while d <= degree {
|
||||
{
|
||||
let next_generator: GenericGFPoly = last_generator.multiply(GenericGFPoly::new(self.field, : vec![i32; 2] = vec![1, self.field.exp(d - 1 + self.field.get_generator_base()), ]
|
||||
));
|
||||
self.cached_generators.add(next_generator);
|
||||
last_generator = next_generator;
|
||||
}
|
||||
d += 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return self.cached_generators.get(degree);
|
||||
}
|
||||
|
||||
pub fn encode(&self, to_encode: &Vec<i32>, ec_bytes: i32) {
|
||||
if ec_bytes == 0 {
|
||||
throw IllegalArgumentException::new("No error correction bytes");
|
||||
}
|
||||
let data_bytes: i32 = to_encode.len() - ec_bytes;
|
||||
if data_bytes <= 0 {
|
||||
throw IllegalArgumentException::new("No data bytes provided");
|
||||
}
|
||||
let generator: GenericGFPoly = self.build_generator(ec_bytes);
|
||||
let info_coefficients: [i32; data_bytes] = [0; data_bytes];
|
||||
System::arraycopy(&to_encode, 0, &info_coefficients, 0, data_bytes);
|
||||
let mut info: GenericGFPoly = GenericGFPoly::new(self.field, &info_coefficients);
|
||||
info = info.multiply_by_monomial(ec_bytes, 1);
|
||||
let remainder: GenericGFPoly = info.divide(generator)[1];
|
||||
let coefficients: Vec<i32> = remainder.get_coefficients();
|
||||
let num_zero_coefficients: i32 = ec_bytes - coefficients.len();
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < num_zero_coefficients {
|
||||
{
|
||||
to_encode[data_bytes + i] = 0;
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
System::arraycopy(&coefficients, 0, &to_encode, data_bytes + num_zero_coefficients, coefficients.len());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* 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::common::reedsolomon;
|
||||
|
||||
/**
|
||||
* <p>Thrown when an exception occurs during Reed-Solomon decoding, such as when
|
||||
* there are too many errors to correct.</p>
|
||||
*
|
||||
* @author Sean Owen
|
||||
*/
|
||||
pub struct ReedSolomonException {
|
||||
super: Exception;
|
||||
}
|
||||
|
||||
impl ReedSolomonException {
|
||||
|
||||
pub fn new( message: &String) -> ReedSolomonException {
|
||||
super(&message);
|
||||
}
|
||||
}
|
||||
|
||||
213
port_src/output/zxing/common/string_utils.rs
Normal file
213
port_src/output/zxing/common/string_utils.rs
Normal file
@@ -0,0 +1,213 @@
|
||||
/*
|
||||
* Copyright (C) 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::common;
|
||||
|
||||
/**
|
||||
* Common string-related functions.
|
||||
*
|
||||
* @author Sean Owen
|
||||
* @author Alex Dupre
|
||||
*/
|
||||
|
||||
const PLATFORM_DEFAULT_ENCODING: Charset = Charset::default_charset();
|
||||
|
||||
const SHIFT_JIS_CHARSET: Charset = Charset::for_name("SJIS");
|
||||
|
||||
const GB2312_CHARSET: Charset = Charset::for_name("GB2312");
|
||||
|
||||
const EUC_JP: Charset = Charset::for_name("EUC_JP");
|
||||
|
||||
const ASSUME_SHIFT_JIS: bool = SHIFT_JIS_CHARSET::equals(&PLATFORM_DEFAULT_ENCODING) || EUC_JP::equals(&PLATFORM_DEFAULT_ENCODING);
|
||||
|
||||
// Retained for ABI compatibility with earlier versions
|
||||
const SHIFT_JIS: &'static str = "SJIS";
|
||||
|
||||
const GB2312: &'static str = "GB2312";
|
||||
pub struct StringUtils {
|
||||
}
|
||||
|
||||
impl StringUtils {
|
||||
|
||||
fn new() -> StringUtils {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bytes bytes encoding a string, whose encoding should be guessed
|
||||
* @param hints decode hints if applicable
|
||||
* @return name of guessed encoding; at the moment will only guess one of:
|
||||
* "SJIS", "UTF8", "ISO8859_1", or the platform default encoding if none
|
||||
* of these can possibly be correct
|
||||
*/
|
||||
pub fn guess_encoding( bytes: &Vec<i8>, hints: &Map<DecodeHintType, ?>) -> String {
|
||||
let c: Charset = ::guess_charset(&bytes, &hints);
|
||||
if c == SHIFT_JIS_CHARSET {
|
||||
return "SJIS";
|
||||
} else if c == StandardCharsets::UTF_8 {
|
||||
return "UTF8";
|
||||
} else if c == StandardCharsets::ISO_8859_1 {
|
||||
return "ISO8859_1";
|
||||
}
|
||||
return c.name();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bytes bytes encoding a string, whose encoding should be guessed
|
||||
* @param hints decode hints if applicable
|
||||
* @return Charset of guessed encoding; at the moment will only guess one of:
|
||||
* {@link #SHIFT_JIS_CHARSET}, {@link StandardCharsets#UTF_8},
|
||||
* {@link StandardCharsets#ISO_8859_1}, {@link StandardCharsets#UTF_16},
|
||||
* or the platform default encoding if
|
||||
* none of these can possibly be correct
|
||||
*/
|
||||
pub fn guess_charset( bytes: &Vec<i8>, hints: &Map<DecodeHintType, ?>) -> Charset {
|
||||
if hints != null && hints.contains_key(DecodeHintType::CHARACTER_SET) {
|
||||
return Charset::for_name(&hints.get(DecodeHintType::CHARACTER_SET).to_string());
|
||||
}
|
||||
// First try UTF-16, assuming anything with its BOM is UTF-16
|
||||
if bytes.len() > 2 && ((bytes[0] == 0xFE as i8 && bytes[1] == 0xFF as i8) || (bytes[0] == 0xFF as i8 && bytes[1] == 0xFE as i8)) {
|
||||
return StandardCharsets::UTF_16;
|
||||
}
|
||||
// For now, merely tries to distinguish ISO-8859-1, UTF-8 and Shift_JIS,
|
||||
// which should be by far the most common encodings.
|
||||
let length: i32 = bytes.len();
|
||||
let can_be_i_s_o88591: bool = true;
|
||||
let can_be_shift_j_i_s: bool = true;
|
||||
let can_be_u_t_f8: bool = true;
|
||||
let utf8_bytes_left: i32 = 0;
|
||||
let utf2_bytes_chars: i32 = 0;
|
||||
let utf3_bytes_chars: i32 = 0;
|
||||
let utf4_bytes_chars: i32 = 0;
|
||||
let sjis_bytes_left: i32 = 0;
|
||||
let sjis_katakana_chars: i32 = 0;
|
||||
let sjis_cur_katakana_word_length: i32 = 0;
|
||||
let sjis_cur_double_bytes_word_length: i32 = 0;
|
||||
let sjis_max_katakana_word_length: i32 = 0;
|
||||
let sjis_max_double_bytes_word_length: i32 = 0;
|
||||
let iso_high_other: i32 = 0;
|
||||
let utf8bom: bool = bytes.len() > 3 && bytes[0] == 0xEF as i8 && bytes[1] == 0xBB as i8 && bytes[2] == 0xBF as i8;
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < length && (can_be_i_s_o88591 || can_be_shift_j_i_s || can_be_u_t_f8) {
|
||||
{
|
||||
let value: i32 = bytes[i] & 0xFF;
|
||||
// UTF-8 stuff
|
||||
if can_be_u_t_f8 {
|
||||
if utf8_bytes_left > 0 {
|
||||
if (value & 0x80) == 0 {
|
||||
can_be_u_t_f8 = false;
|
||||
} else {
|
||||
utf8_bytes_left -= 1;
|
||||
}
|
||||
} else if (value & 0x80) != 0 {
|
||||
if (value & 0x40) == 0 {
|
||||
can_be_u_t_f8 = false;
|
||||
} else {
|
||||
utf8_bytes_left += 1;
|
||||
if (value & 0x20) == 0 {
|
||||
utf2_bytes_chars += 1;
|
||||
} else {
|
||||
utf8_bytes_left += 1;
|
||||
if (value & 0x10) == 0 {
|
||||
utf3_bytes_chars += 1;
|
||||
} else {
|
||||
utf8_bytes_left += 1;
|
||||
if (value & 0x08) == 0 {
|
||||
utf4_bytes_chars += 1;
|
||||
} else {
|
||||
can_be_u_t_f8 = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// ISO-8859-1 stuff
|
||||
if can_be_i_s_o88591 {
|
||||
if value > 0x7F && value < 0xA0 {
|
||||
can_be_i_s_o88591 = false;
|
||||
} else if value > 0x9F && (value < 0xC0 || value == 0xD7 || value == 0xF7) {
|
||||
iso_high_other += 1;
|
||||
}
|
||||
}
|
||||
// Shift_JIS stuff
|
||||
if can_be_shift_j_i_s {
|
||||
if sjis_bytes_left > 0 {
|
||||
if value < 0x40 || value == 0x7F || value > 0xFC {
|
||||
can_be_shift_j_i_s = false;
|
||||
} else {
|
||||
sjis_bytes_left -= 1;
|
||||
}
|
||||
} else if value == 0x80 || value == 0xA0 || value > 0xEF {
|
||||
can_be_shift_j_i_s = false;
|
||||
} else if value > 0xA0 && value < 0xE0 {
|
||||
sjis_katakana_chars += 1;
|
||||
sjis_cur_double_bytes_word_length = 0;
|
||||
sjis_cur_katakana_word_length += 1;
|
||||
if sjis_cur_katakana_word_length > sjis_max_katakana_word_length {
|
||||
sjis_max_katakana_word_length = sjis_cur_katakana_word_length;
|
||||
}
|
||||
} else if value > 0x7F {
|
||||
sjis_bytes_left += 1;
|
||||
//sjisDoubleBytesChars++;
|
||||
sjis_cur_katakana_word_length = 0;
|
||||
sjis_cur_double_bytes_word_length += 1;
|
||||
if sjis_cur_double_bytes_word_length > sjis_max_double_bytes_word_length {
|
||||
sjis_max_double_bytes_word_length = sjis_cur_double_bytes_word_length;
|
||||
}
|
||||
} else {
|
||||
//sjisLowChars++;
|
||||
sjis_cur_katakana_word_length = 0;
|
||||
sjis_cur_double_bytes_word_length = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
if can_be_u_t_f8 && utf8_bytes_left > 0 {
|
||||
can_be_u_t_f8 = false;
|
||||
}
|
||||
if can_be_shift_j_i_s && sjis_bytes_left > 0 {
|
||||
can_be_shift_j_i_s = false;
|
||||
}
|
||||
// Easy -- if there is BOM or at least 1 valid not-single byte character (and no evidence it can't be UTF-8), done
|
||||
if can_be_u_t_f8 && (utf8bom || utf2_bytes_chars + utf3_bytes_chars + utf4_bytes_chars > 0) {
|
||||
return StandardCharsets::UTF_8;
|
||||
}
|
||||
// Easy -- if assuming Shift_JIS or >= 3 valid consecutive not-ascii characters (and no evidence it can't be), done
|
||||
if can_be_shift_j_i_s && (ASSUME_SHIFT_JIS || sjis_max_katakana_word_length >= 3 || sjis_max_double_bytes_word_length >= 3) {
|
||||
return SHIFT_JIS_CHARSET;
|
||||
}
|
||||
// - then we conclude Shift_JIS, else ISO-8859-1
|
||||
if can_be_i_s_o88591 && can_be_shift_j_i_s {
|
||||
return if (sjis_max_katakana_word_length == 2 && sjis_katakana_chars == 2) || iso_high_other * 10 >= length { SHIFT_JIS_CHARSET } else { StandardCharsets::ISO_8859_1 };
|
||||
}
|
||||
// Otherwise, try in order ISO-8859-1, Shift JIS, UTF-8 and fall back to default platform encoding
|
||||
if can_be_i_s_o88591 {
|
||||
return StandardCharsets::ISO_8859_1;
|
||||
}
|
||||
if can_be_shift_j_i_s {
|
||||
return SHIFT_JIS_CHARSET;
|
||||
}
|
||||
if can_be_u_t_f8 {
|
||||
return StandardCharsets::UTF_8;
|
||||
}
|
||||
// Otherwise, we take a wild guess with platform encoding
|
||||
return PLATFORM_DEFAULT_ENCODING;
|
||||
}
|
||||
}
|
||||
|
||||
146
port_src/output/zxing/datamatrix/data_matrix_reader.rs
Normal file
146
port_src/output/zxing/datamatrix/data_matrix_reader.rs
Normal file
@@ -0,0 +1,146 @@
|
||||
/*
|
||||
* 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::datamatrix;
|
||||
|
||||
/**
|
||||
* This implementation can detect and decode Data Matrix codes in an image.
|
||||
*
|
||||
* @author bbrown@google.com (Brian Brown)
|
||||
*/
|
||||
|
||||
const NO_POINTS: [Option<ResultPoint>; 0] = [None; 0];
|
||||
#[derive(Reader)]
|
||||
pub struct DataMatrixReader {
|
||||
|
||||
let decoder: Decoder = Decoder::new();
|
||||
}
|
||||
|
||||
impl DataMatrixReader {
|
||||
|
||||
/**
|
||||
* Locates and decodes a Data Matrix code in an image.
|
||||
*
|
||||
* @return a String representing the content encoded by the Data Matrix code
|
||||
* @throws NotFoundException if a Data Matrix code cannot be found
|
||||
* @throws FormatException if a Data Matrix code cannot be decoded
|
||||
* @throws ChecksumException if error correction fails
|
||||
*/
|
||||
pub fn decode(&self, image: &BinaryBitmap) -> /* throws NotFoundException, ChecksumException, FormatException */Result<Result, Rc<Exception>> {
|
||||
return Ok(self.decode(image, null));
|
||||
}
|
||||
|
||||
pub fn decode(&self, image: &BinaryBitmap, hints: &Map<DecodeHintType, ?>) -> /* throws NotFoundException, ChecksumException, FormatException */Result<Result, Rc<Exception>> {
|
||||
let decoder_result: DecoderResult;
|
||||
let mut points: Vec<ResultPoint>;
|
||||
if hints != null && hints.contains_key(DecodeHintType::PURE_BARCODE) {
|
||||
let bits: BitMatrix = ::extract_pure_bits(&image.get_black_matrix());
|
||||
decoder_result = self.decoder.decode(bits);
|
||||
points = NO_POINTS;
|
||||
} else {
|
||||
let detector_result: DetectorResult = Detector::new(&image.get_black_matrix()).detect();
|
||||
decoder_result = self.decoder.decode(&detector_result.get_bits());
|
||||
points = detector_result.get_points();
|
||||
}
|
||||
let result: Result = Result::new(&decoder_result.get_text(), &decoder_result.get_raw_bytes(), points, BarcodeFormat::DATA_MATRIX);
|
||||
let byte_segments: List<Vec<i8>> = decoder_result.get_byte_segments();
|
||||
if byte_segments != null {
|
||||
result.put_metadata(ResultMetadataType::BYTE_SEGMENTS, &byte_segments);
|
||||
}
|
||||
let ec_level: String = decoder_result.get_e_c_level();
|
||||
if ec_level != null {
|
||||
result.put_metadata(ResultMetadataType::ERROR_CORRECTION_LEVEL, &ec_level);
|
||||
}
|
||||
result.put_metadata(ResultMetadataType::SYMBOLOGY_IDENTIFIER, format!("]d{}", decoder_result.get_symbology_modifier()));
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
pub fn reset(&self) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
/**
|
||||
* This method detects a code in a "pure" image -- that is, pure monochrome image
|
||||
* which contains only an unrotated, unskewed, image of a code, with some white border
|
||||
* around it. This is a specialized method that works exceptionally fast in this special
|
||||
* case.
|
||||
*/
|
||||
fn extract_pure_bits( image: &BitMatrix) -> /* throws NotFoundException */Result<BitMatrix, Rc<Exception>> {
|
||||
let left_top_black: Vec<i32> = image.get_top_left_on_bit();
|
||||
let right_bottom_black: Vec<i32> = image.get_bottom_right_on_bit();
|
||||
if left_top_black == null || right_bottom_black == null {
|
||||
throw NotFoundException::get_not_found_instance();
|
||||
}
|
||||
let module_size: i32 = self.module_size(&left_top_black, image);
|
||||
let mut top: i32 = left_top_black[1];
|
||||
let bottom: i32 = right_bottom_black[1];
|
||||
let mut left: i32 = left_top_black[0];
|
||||
let right: i32 = right_bottom_black[0];
|
||||
let matrix_width: i32 = (right - left + 1) / module_size;
|
||||
let matrix_height: i32 = (bottom - top + 1) / module_size;
|
||||
if matrix_width <= 0 || matrix_height <= 0 {
|
||||
throw NotFoundException::get_not_found_instance();
|
||||
}
|
||||
// Push in the "border" by half the module width so that we start
|
||||
// sampling in the middle of the module. Just in case the image is a
|
||||
// little off, this will help recover.
|
||||
let nudge: i32 = module_size / 2;
|
||||
top += nudge;
|
||||
left += nudge;
|
||||
// Now just read off the bits
|
||||
let bits: BitMatrix = BitMatrix::new(matrix_width, matrix_height);
|
||||
{
|
||||
let mut y: i32 = 0;
|
||||
while y < matrix_height {
|
||||
{
|
||||
let i_offset: i32 = top + y * module_size;
|
||||
{
|
||||
let mut x: i32 = 0;
|
||||
while x < matrix_width {
|
||||
{
|
||||
if image.get(left + x * module_size, i_offset) {
|
||||
bits.set(x, y);
|
||||
}
|
||||
}
|
||||
x += 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
y += 1;
|
||||
}
|
||||
}
|
||||
|
||||
return Ok(bits);
|
||||
}
|
||||
|
||||
fn module_size( left_top_black: &Vec<i32>, image: &BitMatrix) -> /* throws NotFoundException */Result<i32, Rc<Exception>> {
|
||||
let width: i32 = image.get_width();
|
||||
let mut x: i32 = left_top_black[0];
|
||||
let y: i32 = left_top_black[1];
|
||||
while x < width && image.get(x, y) {
|
||||
x += 1;
|
||||
}
|
||||
if x == width {
|
||||
throw NotFoundException::get_not_found_instance();
|
||||
}
|
||||
let module_size: i32 = x - left_top_black[0];
|
||||
if module_size == 0 {
|
||||
throw NotFoundException::get_not_found_instance();
|
||||
}
|
||||
return Ok(module_size);
|
||||
}
|
||||
}
|
||||
|
||||
220
port_src/output/zxing/datamatrix/data_matrix_writer.rs
Normal file
220
port_src/output/zxing/datamatrix/data_matrix_writer.rs
Normal file
@@ -0,0 +1,220 @@
|
||||
/*
|
||||
* 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::datamatrix;
|
||||
|
||||
/**
|
||||
* This object renders a Data Matrix code as a BitMatrix 2D array of greyscale values.
|
||||
*
|
||||
* @author dswitkin@google.com (Daniel Switkin)
|
||||
* @author Guillaume Le Biller Added to zxing lib.
|
||||
*/
|
||||
#[derive(Writer)]
|
||||
pub struct DataMatrixWriter {
|
||||
}
|
||||
|
||||
impl DataMatrixWriter {
|
||||
|
||||
pub fn encode(&self, contents: &String, format: &BarcodeFormat, width: i32, height: i32) -> BitMatrix {
|
||||
return self.encode(&contents, format, width, height, null);
|
||||
}
|
||||
|
||||
pub fn encode(&self, contents: &String, format: &BarcodeFormat, width: i32, height: i32, hints: &Map<EncodeHintType, ?>) -> BitMatrix {
|
||||
if contents.is_empty() {
|
||||
throw IllegalArgumentException::new("Found empty contents");
|
||||
}
|
||||
if format != BarcodeFormat::DATA_MATRIX {
|
||||
throw IllegalArgumentException::new(format!("Can only encode DATA_MATRIX, but got {}", format));
|
||||
}
|
||||
if width < 0 || height < 0 {
|
||||
throw IllegalArgumentException::new(format!("Requested dimensions can't be negative: {}x{}", width, height));
|
||||
}
|
||||
// Try to get force shape & min / max size
|
||||
let mut shape: SymbolShapeHint = SymbolShapeHint::FORCE_NONE;
|
||||
let min_size: Dimension = null;
|
||||
let max_size: Dimension = null;
|
||||
if hints != null {
|
||||
let requested_shape: SymbolShapeHint = hints.get(EncodeHintType::DATA_MATRIX_SHAPE) as SymbolShapeHint;
|
||||
if requested_shape != null {
|
||||
shape = requested_shape;
|
||||
}
|
||||
let requested_min_size: Dimension = hints.get(EncodeHintType::MIN_SIZE) as Dimension;
|
||||
if requested_min_size != null {
|
||||
min_size = requested_min_size;
|
||||
}
|
||||
let requested_max_size: Dimension = hints.get(EncodeHintType::MAX_SIZE) as Dimension;
|
||||
if requested_max_size != null {
|
||||
max_size = requested_max_size;
|
||||
}
|
||||
}
|
||||
//1. step: Data encodation
|
||||
let mut encoded: String;
|
||||
let has_compaction_hint: bool = hints != null && hints.contains_key(EncodeHintType::DATA_MATRIX_COMPACT) && Boolean::parse_boolean(&hints.get(EncodeHintType::DATA_MATRIX_COMPACT).to_string());
|
||||
if has_compaction_hint {
|
||||
let has_g_s1_format_hint: bool = hints.contains_key(EncodeHintType::GS1_FORMAT) && Boolean::parse_boolean(&hints.get(EncodeHintType::GS1_FORMAT).to_string());
|
||||
let mut charset: Charset = null;
|
||||
let has_encoding_hint: bool = hints.contains_key(EncodeHintType::CHARACTER_SET);
|
||||
if has_encoding_hint {
|
||||
charset = Charset::for_name(&hints.get(EncodeHintType::CHARACTER_SET).to_string());
|
||||
}
|
||||
encoded = MinimalEncoder::encode_high_level(&contents, &charset, if has_g_s1_format_hint { 0x1D } else { -1 }, shape);
|
||||
} else {
|
||||
let has_force_c40_hint: bool = hints != null && hints.contains_key(EncodeHintType::FORCE_C40) && Boolean::parse_boolean(&hints.get(EncodeHintType::FORCE_C40).to_string());
|
||||
encoded = HighLevelEncoder::encode_high_level(&contents, shape, min_size, max_size, has_force_c40_hint);
|
||||
}
|
||||
let symbol_info: SymbolInfo = SymbolInfo::lookup(&encoded.length(), shape, min_size, max_size, true);
|
||||
//2. step: ECC generation
|
||||
let codewords: String = ErrorCorrection::encode_e_c_c200(&encoded, symbol_info);
|
||||
//3. step: Module placement in Matrix
|
||||
let placement: DefaultPlacement = DefaultPlacement::new(&codewords, &symbol_info.get_symbol_data_width(), &symbol_info.get_symbol_data_height());
|
||||
placement.place();
|
||||
//4. step: low-level encoding
|
||||
return ::encode_low_level(placement, symbol_info, width, height);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode the given symbol info to a bit matrix.
|
||||
*
|
||||
* @param placement The DataMatrix placement.
|
||||
* @param symbolInfo The symbol info to encode.
|
||||
* @return The bit matrix generated.
|
||||
*/
|
||||
fn encode_low_level( placement: &DefaultPlacement, symbol_info: &SymbolInfo, width: i32, height: i32) -> BitMatrix {
|
||||
let symbol_width: i32 = symbol_info.get_symbol_data_width();
|
||||
let symbol_height: i32 = symbol_info.get_symbol_data_height();
|
||||
let matrix: ByteMatrix = ByteMatrix::new(&symbol_info.get_symbol_width(), &symbol_info.get_symbol_height());
|
||||
let matrix_y: i32 = 0;
|
||||
{
|
||||
let mut y: i32 = 0;
|
||||
while y < symbol_height {
|
||||
{
|
||||
// Fill the top edge with alternate 0 / 1
|
||||
let matrix_x: i32;
|
||||
if (y % symbol_info.matrixHeight) == 0 {
|
||||
matrix_x = 0;
|
||||
{
|
||||
let mut x: i32 = 0;
|
||||
while x < symbol_info.get_symbol_width() {
|
||||
{
|
||||
matrix.set(matrix_x, matrix_y, (x % 2) == 0);
|
||||
matrix_x += 1;
|
||||
}
|
||||
x += 1;
|
||||
}
|
||||
}
|
||||
|
||||
matrix_y += 1;
|
||||
}
|
||||
matrix_x = 0;
|
||||
{
|
||||
let mut x: i32 = 0;
|
||||
while x < symbol_width {
|
||||
{
|
||||
// Fill the right edge with full 1
|
||||
if (x % symbol_info.matrixWidth) == 0 {
|
||||
matrix.set(matrix_x, matrix_y, true);
|
||||
matrix_x += 1;
|
||||
}
|
||||
matrix.set(matrix_x, matrix_y, &placement.get_bit(x, y));
|
||||
matrix_x += 1;
|
||||
// Fill the right edge with alternate 0 / 1
|
||||
if (x % symbol_info.matrixWidth) == symbol_info.matrixWidth - 1 {
|
||||
matrix.set(matrix_x, matrix_y, (y % 2) == 0);
|
||||
matrix_x += 1;
|
||||
}
|
||||
}
|
||||
x += 1;
|
||||
}
|
||||
}
|
||||
|
||||
matrix_y += 1;
|
||||
// Fill the bottom edge with full 1
|
||||
if (y % symbol_info.matrixHeight) == symbol_info.matrixHeight - 1 {
|
||||
matrix_x = 0;
|
||||
{
|
||||
let mut x: i32 = 0;
|
||||
while x < symbol_info.get_symbol_width() {
|
||||
{
|
||||
matrix.set(matrix_x, matrix_y, true);
|
||||
matrix_x += 1;
|
||||
}
|
||||
x += 1;
|
||||
}
|
||||
}
|
||||
|
||||
matrix_y += 1;
|
||||
}
|
||||
}
|
||||
y += 1;
|
||||
}
|
||||
}
|
||||
|
||||
return ::convert_byte_matrix_to_bit_matrix(matrix, width, height);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the ByteMatrix to BitMatrix.
|
||||
*
|
||||
* @param reqHeight The requested height of the image (in pixels) with the Datamatrix code
|
||||
* @param reqWidth The requested width of the image (in pixels) with the Datamatrix code
|
||||
* @param matrix The input matrix.
|
||||
* @return The output matrix.
|
||||
*/
|
||||
fn convert_byte_matrix_to_bit_matrix( matrix: &ByteMatrix, req_width: i32, req_height: i32) -> BitMatrix {
|
||||
let matrix_width: i32 = matrix.get_width();
|
||||
let matrix_height: i32 = matrix.get_height();
|
||||
let output_width: i32 = Math::max(req_width, matrix_width);
|
||||
let output_height: i32 = Math::max(req_height, matrix_height);
|
||||
let multiple: i32 = Math::min(output_width / matrix_width, output_height / matrix_height);
|
||||
let left_padding: i32 = (output_width - (matrix_width * multiple)) / 2;
|
||||
let top_padding: i32 = (output_height - (matrix_height * multiple)) / 2;
|
||||
let mut output: BitMatrix;
|
||||
// remove padding if requested width and height are too small
|
||||
if req_height < matrix_height || req_width < matrix_width {
|
||||
left_padding = 0;
|
||||
top_padding = 0;
|
||||
output = BitMatrix::new(matrix_width, matrix_height);
|
||||
} else {
|
||||
output = BitMatrix::new(req_width, req_height);
|
||||
}
|
||||
output.clear();
|
||||
{
|
||||
let input_y: i32 = 0, let output_y: i32 = top_padding;
|
||||
while input_y < matrix_height {
|
||||
{
|
||||
// Write the contents of this row of the bytematrix
|
||||
{
|
||||
let input_x: i32 = 0, let output_x: i32 = left_padding;
|
||||
while input_x < matrix_width {
|
||||
{
|
||||
if matrix.get(input_x, input_y) == 1 {
|
||||
output.set_region(output_x, output_y, multiple, multiple);
|
||||
}
|
||||
}
|
||||
input_x += 1;
|
||||
output_x += multiple;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
input_y += 1;
|
||||
output_y += multiple;
|
||||
}
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
}
|
||||
|
||||
459
port_src/output/zxing/datamatrix/decoder/bit_matrix_parser.rs
Normal file
459
port_src/output/zxing/datamatrix/decoder/bit_matrix_parser.rs
Normal file
@@ -0,0 +1,459 @@
|
||||
/*
|
||||
* 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::datamatrix::decoder;
|
||||
|
||||
/**
|
||||
* @author bbrown@google.com (Brian Brown)
|
||||
*/
|
||||
struct BitMatrixParser {
|
||||
|
||||
let mapping_bit_matrix: BitMatrix;
|
||||
|
||||
let read_mapping_matrix: BitMatrix;
|
||||
|
||||
let mut version: Version;
|
||||
}
|
||||
|
||||
impl BitMatrixParser {
|
||||
|
||||
/**
|
||||
* @param bitMatrix {@link BitMatrix} to parse
|
||||
* @throws FormatException if dimension is < 8 or > 144 or not 0 mod 2
|
||||
*/
|
||||
fn new( bit_matrix: &BitMatrix) -> BitMatrixParser throws FormatException {
|
||||
let dimension: i32 = bit_matrix.get_height();
|
||||
if dimension < 8 || dimension > 144 || (dimension & 0x01) != 0 {
|
||||
throw FormatException::get_format_instance();
|
||||
}
|
||||
version = ::read_version(bit_matrix);
|
||||
let .mappingBitMatrix = self.extract_data_region(bit_matrix);
|
||||
let .readMappingMatrix = BitMatrix::new(&let .mappingBitMatrix.get_width(), &let .mappingBitMatrix.get_height());
|
||||
}
|
||||
|
||||
fn get_version(&self) -> Version {
|
||||
return self.version;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Creates the version object based on the dimension of the original bit matrix from
|
||||
* the datamatrix code.</p>
|
||||
*
|
||||
* <p>See ISO 16022:2006 Table 7 - ECC 200 symbol attributes</p>
|
||||
*
|
||||
* @param bitMatrix Original {@link BitMatrix} including alignment patterns
|
||||
* @return {@link Version} encapsulating the Data Matrix Code's "version"
|
||||
* @throws FormatException if the dimensions of the mapping matrix are not valid
|
||||
* Data Matrix dimensions.
|
||||
*/
|
||||
fn read_version( bit_matrix: &BitMatrix) -> /* throws FormatException */Result<Version, Rc<Exception>> {
|
||||
let num_rows: i32 = bit_matrix.get_height();
|
||||
let num_columns: i32 = bit_matrix.get_width();
|
||||
return Ok(Version::get_version_for_dimensions(num_rows, num_columns));
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Reads the bits in the {@link BitMatrix} representing the mapping matrix (No alignment patterns)
|
||||
* in the correct order in order to reconstitute the codewords bytes contained within the
|
||||
* Data Matrix Code.</p>
|
||||
*
|
||||
* @return bytes encoded within the Data Matrix Code
|
||||
* @throws FormatException if the exact number of bytes expected is not read
|
||||
*/
|
||||
fn read_codewords(&self) -> /* throws FormatException */Result<Vec<i8>, Rc<Exception>> {
|
||||
let mut result: [i8; self.version.get_total_codewords()] = [0; self.version.get_total_codewords()];
|
||||
let result_offset: i32 = 0;
|
||||
let mut row: i32 = 4;
|
||||
let mut column: i32 = 0;
|
||||
let num_rows: i32 = self.mapping_bit_matrix.get_height();
|
||||
let num_columns: i32 = self.mapping_bit_matrix.get_width();
|
||||
let corner1_read: bool = false;
|
||||
let corner2_read: bool = false;
|
||||
let corner3_read: bool = false;
|
||||
let corner4_read: bool = false;
|
||||
// Read all of the codewords
|
||||
loop { {
|
||||
// Check the four corner cases
|
||||
if (row == num_rows) && (column == 0) && !corner1_read {
|
||||
result[result_offset += 1 !!!check!!! post increment] = self.read_corner1(num_rows, num_columns) as i8;
|
||||
row -= 2;
|
||||
column += 2;
|
||||
corner1_read = true;
|
||||
} else if (row == num_rows - 2) && (column == 0) && ((num_columns & 0x03) != 0) && !corner2_read {
|
||||
result[result_offset += 1 !!!check!!! post increment] = self.read_corner2(num_rows, num_columns) as i8;
|
||||
row -= 2;
|
||||
column += 2;
|
||||
corner2_read = true;
|
||||
} else if (row == num_rows + 4) && (column == 2) && ((num_columns & 0x07) == 0) && !corner3_read {
|
||||
result[result_offset += 1 !!!check!!! post increment] = self.read_corner3(num_rows, num_columns) as i8;
|
||||
row -= 2;
|
||||
column += 2;
|
||||
corner3_read = true;
|
||||
} else if (row == num_rows - 2) && (column == 0) && ((num_columns & 0x07) == 4) && !corner4_read {
|
||||
result[result_offset += 1 !!!check!!! post increment] = self.read_corner4(num_rows, num_columns) as i8;
|
||||
row -= 2;
|
||||
column += 2;
|
||||
corner4_read = true;
|
||||
} else {
|
||||
// Sweep upward diagonally to the right
|
||||
loop { {
|
||||
if (row < num_rows) && (column >= 0) && !self.read_mapping_matrix.get(column, row) {
|
||||
result[result_offset += 1 !!!check!!! post increment] = self.read_utah(row, column, num_rows, num_columns) as i8;
|
||||
}
|
||||
row -= 2;
|
||||
column += 2;
|
||||
}if !((row >= 0) && (column < num_columns)) break;}
|
||||
row += 1;
|
||||
column += 3;
|
||||
// Sweep downward diagonally to the left
|
||||
loop { {
|
||||
if (row >= 0) && (column < num_columns) && !self.read_mapping_matrix.get(column, row) {
|
||||
result[result_offset += 1 !!!check!!! post increment] = self.read_utah(row, column, num_rows, num_columns) as i8;
|
||||
}
|
||||
row += 2;
|
||||
column -= 2;
|
||||
}if !((row < num_rows) && (column >= 0)) break;}
|
||||
row += 3;
|
||||
column += 1;
|
||||
}
|
||||
}if !((row < num_rows) || (column < num_columns)) break;}
|
||||
if result_offset != self.version.get_total_codewords() {
|
||||
throw FormatException::get_format_instance();
|
||||
}
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Reads a bit of the mapping matrix accounting for boundary wrapping.</p>
|
||||
*
|
||||
* @param row Row to read in the mapping matrix
|
||||
* @param column Column to read in the mapping matrix
|
||||
* @param numRows Number of rows in the mapping matrix
|
||||
* @param numColumns Number of columns in the mapping matrix
|
||||
* @return value of the given bit in the mapping matrix
|
||||
*/
|
||||
fn read_module(&self, row: i32, column: i32, num_rows: i32, num_columns: i32) -> bool {
|
||||
// Adjust the row and column indices based on boundary wrapping
|
||||
if row < 0 {
|
||||
row += num_rows;
|
||||
column += 4 - ((num_rows + 4) & 0x07);
|
||||
}
|
||||
if column < 0 {
|
||||
column += num_columns;
|
||||
row += 4 - ((num_columns + 4) & 0x07);
|
||||
}
|
||||
if row >= num_rows {
|
||||
row -= num_rows;
|
||||
}
|
||||
self.read_mapping_matrix.set(column, row);
|
||||
return self.mapping_bit_matrix.get(column, row);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Reads the 8 bits of the standard Utah-shaped pattern.</p>
|
||||
*
|
||||
* <p>See ISO 16022:2006, 5.8.1 Figure 6</p>
|
||||
*
|
||||
* @param row Current row in the mapping matrix, anchored at the 8th bit (LSB) of the pattern
|
||||
* @param column Current column in the mapping matrix, anchored at the 8th bit (LSB) of the pattern
|
||||
* @param numRows Number of rows in the mapping matrix
|
||||
* @param numColumns Number of columns in the mapping matrix
|
||||
* @return byte from the utah shape
|
||||
*/
|
||||
fn read_utah(&self, row: i32, column: i32, num_rows: i32, num_columns: i32) -> i32 {
|
||||
let current_byte: i32 = 0;
|
||||
if self.read_module(row - 2, column - 2, num_rows, num_columns) {
|
||||
current_byte |= 1;
|
||||
}
|
||||
current_byte <<= 1;
|
||||
if self.read_module(row - 2, column - 1, num_rows, num_columns) {
|
||||
current_byte |= 1;
|
||||
}
|
||||
current_byte <<= 1;
|
||||
if self.read_module(row - 1, column - 2, num_rows, num_columns) {
|
||||
current_byte |= 1;
|
||||
}
|
||||
current_byte <<= 1;
|
||||
if self.read_module(row - 1, column - 1, num_rows, num_columns) {
|
||||
current_byte |= 1;
|
||||
}
|
||||
current_byte <<= 1;
|
||||
if self.read_module(row - 1, column, num_rows, num_columns) {
|
||||
current_byte |= 1;
|
||||
}
|
||||
current_byte <<= 1;
|
||||
if self.read_module(row, column - 2, num_rows, num_columns) {
|
||||
current_byte |= 1;
|
||||
}
|
||||
current_byte <<= 1;
|
||||
if self.read_module(row, column - 1, num_rows, num_columns) {
|
||||
current_byte |= 1;
|
||||
}
|
||||
current_byte <<= 1;
|
||||
if self.read_module(row, column, num_rows, num_columns) {
|
||||
current_byte |= 1;
|
||||
}
|
||||
return current_byte;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Reads the 8 bits of the special corner condition 1.</p>
|
||||
*
|
||||
* <p>See ISO 16022:2006, Figure F.3</p>
|
||||
*
|
||||
* @param numRows Number of rows in the mapping matrix
|
||||
* @param numColumns Number of columns in the mapping matrix
|
||||
* @return byte from the Corner condition 1
|
||||
*/
|
||||
fn read_corner1(&self, num_rows: i32, num_columns: i32) -> i32 {
|
||||
let current_byte: i32 = 0;
|
||||
if self.read_module(num_rows - 1, 0, num_rows, num_columns) {
|
||||
current_byte |= 1;
|
||||
}
|
||||
current_byte <<= 1;
|
||||
if self.read_module(num_rows - 1, 1, num_rows, num_columns) {
|
||||
current_byte |= 1;
|
||||
}
|
||||
current_byte <<= 1;
|
||||
if self.read_module(num_rows - 1, 2, num_rows, num_columns) {
|
||||
current_byte |= 1;
|
||||
}
|
||||
current_byte <<= 1;
|
||||
if self.read_module(0, num_columns - 2, num_rows, num_columns) {
|
||||
current_byte |= 1;
|
||||
}
|
||||
current_byte <<= 1;
|
||||
if self.read_module(0, num_columns - 1, num_rows, num_columns) {
|
||||
current_byte |= 1;
|
||||
}
|
||||
current_byte <<= 1;
|
||||
if self.read_module(1, num_columns - 1, num_rows, num_columns) {
|
||||
current_byte |= 1;
|
||||
}
|
||||
current_byte <<= 1;
|
||||
if self.read_module(2, num_columns - 1, num_rows, num_columns) {
|
||||
current_byte |= 1;
|
||||
}
|
||||
current_byte <<= 1;
|
||||
if self.read_module(3, num_columns - 1, num_rows, num_columns) {
|
||||
current_byte |= 1;
|
||||
}
|
||||
return current_byte;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Reads the 8 bits of the special corner condition 2.</p>
|
||||
*
|
||||
* <p>See ISO 16022:2006, Figure F.4</p>
|
||||
*
|
||||
* @param numRows Number of rows in the mapping matrix
|
||||
* @param numColumns Number of columns in the mapping matrix
|
||||
* @return byte from the Corner condition 2
|
||||
*/
|
||||
fn read_corner2(&self, num_rows: i32, num_columns: i32) -> i32 {
|
||||
let current_byte: i32 = 0;
|
||||
if self.read_module(num_rows - 3, 0, num_rows, num_columns) {
|
||||
current_byte |= 1;
|
||||
}
|
||||
current_byte <<= 1;
|
||||
if self.read_module(num_rows - 2, 0, num_rows, num_columns) {
|
||||
current_byte |= 1;
|
||||
}
|
||||
current_byte <<= 1;
|
||||
if self.read_module(num_rows - 1, 0, num_rows, num_columns) {
|
||||
current_byte |= 1;
|
||||
}
|
||||
current_byte <<= 1;
|
||||
if self.read_module(0, num_columns - 4, num_rows, num_columns) {
|
||||
current_byte |= 1;
|
||||
}
|
||||
current_byte <<= 1;
|
||||
if self.read_module(0, num_columns - 3, num_rows, num_columns) {
|
||||
current_byte |= 1;
|
||||
}
|
||||
current_byte <<= 1;
|
||||
if self.read_module(0, num_columns - 2, num_rows, num_columns) {
|
||||
current_byte |= 1;
|
||||
}
|
||||
current_byte <<= 1;
|
||||
if self.read_module(0, num_columns - 1, num_rows, num_columns) {
|
||||
current_byte |= 1;
|
||||
}
|
||||
current_byte <<= 1;
|
||||
if self.read_module(1, num_columns - 1, num_rows, num_columns) {
|
||||
current_byte |= 1;
|
||||
}
|
||||
return current_byte;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Reads the 8 bits of the special corner condition 3.</p>
|
||||
*
|
||||
* <p>See ISO 16022:2006, Figure F.5</p>
|
||||
*
|
||||
* @param numRows Number of rows in the mapping matrix
|
||||
* @param numColumns Number of columns in the mapping matrix
|
||||
* @return byte from the Corner condition 3
|
||||
*/
|
||||
fn read_corner3(&self, num_rows: i32, num_columns: i32) -> i32 {
|
||||
let current_byte: i32 = 0;
|
||||
if self.read_module(num_rows - 1, 0, num_rows, num_columns) {
|
||||
current_byte |= 1;
|
||||
}
|
||||
current_byte <<= 1;
|
||||
if self.read_module(num_rows - 1, num_columns - 1, num_rows, num_columns) {
|
||||
current_byte |= 1;
|
||||
}
|
||||
current_byte <<= 1;
|
||||
if self.read_module(0, num_columns - 3, num_rows, num_columns) {
|
||||
current_byte |= 1;
|
||||
}
|
||||
current_byte <<= 1;
|
||||
if self.read_module(0, num_columns - 2, num_rows, num_columns) {
|
||||
current_byte |= 1;
|
||||
}
|
||||
current_byte <<= 1;
|
||||
if self.read_module(0, num_columns - 1, num_rows, num_columns) {
|
||||
current_byte |= 1;
|
||||
}
|
||||
current_byte <<= 1;
|
||||
if self.read_module(1, num_columns - 3, num_rows, num_columns) {
|
||||
current_byte |= 1;
|
||||
}
|
||||
current_byte <<= 1;
|
||||
if self.read_module(1, num_columns - 2, num_rows, num_columns) {
|
||||
current_byte |= 1;
|
||||
}
|
||||
current_byte <<= 1;
|
||||
if self.read_module(1, num_columns - 1, num_rows, num_columns) {
|
||||
current_byte |= 1;
|
||||
}
|
||||
return current_byte;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Reads the 8 bits of the special corner condition 4.</p>
|
||||
*
|
||||
* <p>See ISO 16022:2006, Figure F.6</p>
|
||||
*
|
||||
* @param numRows Number of rows in the mapping matrix
|
||||
* @param numColumns Number of columns in the mapping matrix
|
||||
* @return byte from the Corner condition 4
|
||||
*/
|
||||
fn read_corner4(&self, num_rows: i32, num_columns: i32) -> i32 {
|
||||
let current_byte: i32 = 0;
|
||||
if self.read_module(num_rows - 3, 0, num_rows, num_columns) {
|
||||
current_byte |= 1;
|
||||
}
|
||||
current_byte <<= 1;
|
||||
if self.read_module(num_rows - 2, 0, num_rows, num_columns) {
|
||||
current_byte |= 1;
|
||||
}
|
||||
current_byte <<= 1;
|
||||
if self.read_module(num_rows - 1, 0, num_rows, num_columns) {
|
||||
current_byte |= 1;
|
||||
}
|
||||
current_byte <<= 1;
|
||||
if self.read_module(0, num_columns - 2, num_rows, num_columns) {
|
||||
current_byte |= 1;
|
||||
}
|
||||
current_byte <<= 1;
|
||||
if self.read_module(0, num_columns - 1, num_rows, num_columns) {
|
||||
current_byte |= 1;
|
||||
}
|
||||
current_byte <<= 1;
|
||||
if self.read_module(1, num_columns - 1, num_rows, num_columns) {
|
||||
current_byte |= 1;
|
||||
}
|
||||
current_byte <<= 1;
|
||||
if self.read_module(2, num_columns - 1, num_rows, num_columns) {
|
||||
current_byte |= 1;
|
||||
}
|
||||
current_byte <<= 1;
|
||||
if self.read_module(3, num_columns - 1, num_rows, num_columns) {
|
||||
current_byte |= 1;
|
||||
}
|
||||
return current_byte;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Extracts the data region from a {@link BitMatrix} that contains
|
||||
* alignment patterns.</p>
|
||||
*
|
||||
* @param bitMatrix Original {@link BitMatrix} with alignment patterns
|
||||
* @return BitMatrix that has the alignment patterns removed
|
||||
*/
|
||||
fn extract_data_region(&self, bit_matrix: &BitMatrix) -> BitMatrix {
|
||||
let symbol_size_rows: i32 = self.version.get_symbol_size_rows();
|
||||
let symbol_size_columns: i32 = self.version.get_symbol_size_columns();
|
||||
if bit_matrix.get_height() != symbol_size_rows {
|
||||
throw IllegalArgumentException::new("Dimension of bitMatrix must match the version size");
|
||||
}
|
||||
let data_region_size_rows: i32 = self.version.get_data_region_size_rows();
|
||||
let data_region_size_columns: i32 = self.version.get_data_region_size_columns();
|
||||
let num_data_regions_row: i32 = symbol_size_rows / data_region_size_rows;
|
||||
let num_data_regions_column: i32 = symbol_size_columns / data_region_size_columns;
|
||||
let size_data_region_row: i32 = num_data_regions_row * data_region_size_rows;
|
||||
let size_data_region_column: i32 = num_data_regions_column * data_region_size_columns;
|
||||
let bit_matrix_without_alignment: BitMatrix = BitMatrix::new(size_data_region_column, size_data_region_row);
|
||||
{
|
||||
let data_region_row: i32 = 0;
|
||||
while data_region_row < num_data_regions_row {
|
||||
{
|
||||
let data_region_row_offset: i32 = data_region_row * data_region_size_rows;
|
||||
{
|
||||
let data_region_column: i32 = 0;
|
||||
while data_region_column < num_data_regions_column {
|
||||
{
|
||||
let data_region_column_offset: i32 = data_region_column * data_region_size_columns;
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < data_region_size_rows {
|
||||
{
|
||||
let read_row_offset: i32 = data_region_row * (data_region_size_rows + 2) + 1 + i;
|
||||
let write_row_offset: i32 = data_region_row_offset + i;
|
||||
{
|
||||
let mut j: i32 = 0;
|
||||
while j < data_region_size_columns {
|
||||
{
|
||||
let read_column_offset: i32 = data_region_column * (data_region_size_columns + 2) + 1 + j;
|
||||
if bit_matrix.get(read_column_offset, read_row_offset) {
|
||||
let write_column_offset: i32 = data_region_column_offset + j;
|
||||
bit_matrix_without_alignment.set(write_column_offset, write_row_offset);
|
||||
}
|
||||
}
|
||||
j += 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
data_region_column += 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
data_region_row += 1;
|
||||
}
|
||||
}
|
||||
|
||||
return bit_matrix_without_alignment;
|
||||
}
|
||||
}
|
||||
|
||||
154
port_src/output/zxing/datamatrix/decoder/data_block.rs
Normal file
154
port_src/output/zxing/datamatrix/decoder/data_block.rs
Normal file
@@ -0,0 +1,154 @@
|
||||
/*
|
||||
* 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::datamatrix::decoder;
|
||||
|
||||
/**
|
||||
* <p>Encapsulates a block of data within a Data Matrix Code. Data Matrix Codes may split their data into
|
||||
* multiple blocks, each of which is a unit of data and error-correction codewords. Each
|
||||
* is represented by an instance of this class.</p>
|
||||
*
|
||||
* @author bbrown@google.com (Brian Brown)
|
||||
*/
|
||||
struct DataBlock {
|
||||
|
||||
let num_data_codewords: i32;
|
||||
|
||||
let mut codewords: Vec<i8>;
|
||||
}
|
||||
|
||||
impl DataBlock {
|
||||
|
||||
fn new( num_data_codewords: i32, codewords: &Vec<i8>) -> DataBlock {
|
||||
let .numDataCodewords = num_data_codewords;
|
||||
let .codewords = codewords;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>When Data Matrix Codes use multiple data blocks, they actually interleave the bytes of each of them.
|
||||
* That is, the first byte of data block 1 to n is written, then the second bytes, and so on. This
|
||||
* method will separate the data into original blocks.</p>
|
||||
*
|
||||
* @param rawCodewords bytes as read directly from the Data Matrix Code
|
||||
* @param version version of the Data Matrix Code
|
||||
* @return DataBlocks containing original bytes, "de-interleaved" from representation in the
|
||||
* Data Matrix Code
|
||||
*/
|
||||
fn get_data_blocks( raw_codewords: &Vec<i8>, version: &Version) -> Vec<DataBlock> {
|
||||
// Figure out the number and size of data blocks used by this version
|
||||
let ec_blocks: Version.ECBlocks = version.get_e_c_blocks();
|
||||
// First count the total number of data blocks
|
||||
let total_blocks: i32 = 0;
|
||||
let ec_block_array: Vec<Version.ECB> = ec_blocks.get_e_c_blocks();
|
||||
for let ec_block: Version.ECB in ec_block_array {
|
||||
total_blocks += ec_block.get_count();
|
||||
}
|
||||
// Now establish DataBlocks of the appropriate size and number of data codewords
|
||||
let mut result: [Option<DataBlock>; total_blocks] = [None; total_blocks];
|
||||
let num_result_blocks: i32 = 0;
|
||||
for let ec_block: Version.ECB in ec_block_array {
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < ec_block.get_count() {
|
||||
{
|
||||
let num_data_codewords: i32 = ec_block.get_data_codewords();
|
||||
let num_block_codewords: i32 = ec_blocks.get_e_c_codewords() + num_data_codewords;
|
||||
result[num_result_blocks += 1 !!!check!!! post increment] = DataBlock::new(num_data_codewords, : [i8; num_block_codewords] = [0; num_block_codewords]);
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
// All blocks have the same amount of data, except that the last n
|
||||
// (where n may be 0) have 1 less byte. Figure out where these start.
|
||||
// TODO(bbrown): There is only one case where there is a difference for Data Matrix for size 144
|
||||
let longer_blocks_total_codewords: i32 = result[0].codewords.len();
|
||||
//int shorterBlocksTotalCodewords = longerBlocksTotalCodewords - 1;
|
||||
let longer_blocks_num_data_codewords: i32 = longer_blocks_total_codewords - ec_blocks.get_e_c_codewords();
|
||||
let shorter_blocks_num_data_codewords: i32 = longer_blocks_num_data_codewords - 1;
|
||||
// The last elements of result may be 1 element shorter for 144 matrix
|
||||
// first fill out as many elements as all of them have minus 1
|
||||
let raw_codewords_offset: i32 = 0;
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < shorter_blocks_num_data_codewords {
|
||||
{
|
||||
{
|
||||
let mut j: i32 = 0;
|
||||
while j < num_result_blocks {
|
||||
{
|
||||
result[j].codewords[i] = raw_codewords[raw_codewords_offset += 1 !!!check!!! post increment];
|
||||
}
|
||||
j += 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Fill out the last data block in the longer ones
|
||||
let special_version: bool = version.get_version_number() == 24;
|
||||
let num_longer_blocks: i32 = if special_version { 8 } else { num_result_blocks };
|
||||
{
|
||||
let mut j: i32 = 0;
|
||||
while j < num_longer_blocks {
|
||||
{
|
||||
result[j].codewords[longer_blocks_num_data_codewords - 1] = raw_codewords[raw_codewords_offset += 1 !!!check!!! post increment];
|
||||
}
|
||||
j += 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Now add in error correction blocks
|
||||
let max: i32 = result[0].codewords.len();
|
||||
{
|
||||
let mut i: i32 = longer_blocks_num_data_codewords;
|
||||
while i < max {
|
||||
{
|
||||
{
|
||||
let mut j: i32 = 0;
|
||||
while j < num_result_blocks {
|
||||
{
|
||||
let j_offset: i32 = if special_version { (j + 8) % num_result_blocks } else { j };
|
||||
let i_offset: i32 = if special_version && j_offset > 7 { i - 1 } else { i };
|
||||
result[j_offset].codewords[i_offset] = raw_codewords[raw_codewords_offset += 1 !!!check!!! post increment];
|
||||
}
|
||||
j += 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
if raw_codewords_offset != raw_codewords.len() {
|
||||
throw IllegalArgumentException::new();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
fn get_num_data_codewords(&self) -> i32 {
|
||||
return self.num_data_codewords;
|
||||
}
|
||||
|
||||
fn get_codewords(&self) -> Vec<i8> {
|
||||
return self.codewords;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,679 @@
|
||||
/*
|
||||
* 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::datamatrix::decoder;
|
||||
|
||||
/**
|
||||
* <p>Data Matrix Codes can encode text as bits in one of several modes, and can use multiple modes
|
||||
* in one Data Matrix Code. This class decodes the bits back into text.</p>
|
||||
*
|
||||
* <p>See ISO 16022:2006, 5.2.1 - 5.2.9.2</p>
|
||||
*
|
||||
* @author bbrown@google.com (Brian Brown)
|
||||
* @author Sean Owen
|
||||
*/
|
||||
|
||||
/**
|
||||
* See ISO 16022:2006, Annex C Table C.1
|
||||
* The C40 Basic Character Set (*'s used for placeholders for the shift values)
|
||||
*/
|
||||
const C40_BASIC_SET_CHARS: vec![Vec<char>; 40] = vec!['*', '*', '*', ' ', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', ]
|
||||
;
|
||||
|
||||
const C40_SHIFT2_SET_CHARS: vec![Vec<char>; 27] = vec!['!', '"', '#', '$', '%', '&', '\'', '(', ')', '*', '+', ',', '-', '.', '/', ':', ';', '<', '=', '>', '?', '@', '[', '\\', ']', '^', '_', ]
|
||||
;
|
||||
|
||||
const TEXT_BASIC_SET_CHARS: vec![Vec<char>; 40] = vec!['*', '*', '*', ' ', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', ]
|
||||
;
|
||||
|
||||
// Shift 2 for Text is the same encoding as C40
|
||||
const TEXT_SHIFT2_SET_CHARS: Vec<char> = C40_SHIFT2_SET_CHARS;
|
||||
|
||||
const TEXT_SHIFT3_SET_CHARS: vec![Vec<char>; 32] = vec!['`', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '{', '|', '}', '~', 127 as char, ]
|
||||
;
|
||||
struct DecodedBitStreamParser {
|
||||
}
|
||||
|
||||
impl DecodedBitStreamParser {
|
||||
|
||||
enum Mode {
|
||||
|
||||
// Not really a mode
|
||||
PAD_ENCODE(), ASCII_ENCODE(), C40_ENCODE(), TEXT_ENCODE(), ANSIX12_ENCODE(), EDIFACT_ENCODE(), BASE256_ENCODE(), ECI_ENCODE()
|
||||
}
|
||||
|
||||
fn new() -> DecodedBitStreamParser {
|
||||
}
|
||||
|
||||
fn decode( bytes: &Vec<i8>) -> /* throws FormatException */Result<DecoderResult, Rc<Exception>> {
|
||||
let bits: BitSource = BitSource::new(&bytes);
|
||||
let result: ECIStringBuilder = ECIStringBuilder::new(100);
|
||||
let result_trailer: StringBuilder = StringBuilder::new(0);
|
||||
let byte_segments: List<Vec<i8>> = ArrayList<>::new(1);
|
||||
let mut mode: Mode = Mode::ASCII_ENCODE;
|
||||
// Could look directly at 'bytes', if we're sure of not having to account for multi byte values
|
||||
let fnc1_positions: Set<Integer> = HashSet<>::new();
|
||||
let symbology_modifier: i32;
|
||||
let is_e_c_iencoded: bool = false;
|
||||
loop { {
|
||||
if mode == Mode::ASCII_ENCODE {
|
||||
mode = ::decode_ascii_segment(bits, result, &result_trailer, &fnc1_positions);
|
||||
} else {
|
||||
match mode {
|
||||
C40_ENCODE =>
|
||||
{
|
||||
::decode_c40_segment(bits, result, &fnc1_positions);
|
||||
break;
|
||||
}
|
||||
TEXT_ENCODE =>
|
||||
{
|
||||
::decode_text_segment(bits, result, &fnc1_positions);
|
||||
break;
|
||||
}
|
||||
ANSIX12_ENCODE =>
|
||||
{
|
||||
::decode_ansi_x12_segment(bits, result);
|
||||
break;
|
||||
}
|
||||
EDIFACT_ENCODE =>
|
||||
{
|
||||
::decode_edifact_segment(bits, result);
|
||||
break;
|
||||
}
|
||||
BASE256_ENCODE =>
|
||||
{
|
||||
::decode_base256_segment(bits, result, &byte_segments);
|
||||
break;
|
||||
}
|
||||
ECI_ENCODE =>
|
||||
{
|
||||
::decode_e_c_i_segment(bits, result);
|
||||
// ECI detection only, atm continue decoding as ASCII
|
||||
is_e_c_iencoded = true;
|
||||
break;
|
||||
}
|
||||
_ =>
|
||||
{
|
||||
throw FormatException::get_format_instance();
|
||||
}
|
||||
}
|
||||
mode = Mode::ASCII_ENCODE;
|
||||
}
|
||||
}if !(mode != Mode::PAD_ENCODE && bits.available() > 0) break;}
|
||||
if result_trailer.length() > 0 {
|
||||
result.append_characters(&result_trailer);
|
||||
}
|
||||
if is_e_c_iencoded {
|
||||
// https://honeywellaidc.force.com/supportppr/s/article/List-of-barcode-symbology-AIM-Identifiers
|
||||
if fnc1_positions.contains(0) || fnc1_positions.contains(4) {
|
||||
symbology_modifier = 5;
|
||||
} else if fnc1_positions.contains(1) || fnc1_positions.contains(5) {
|
||||
symbology_modifier = 6;
|
||||
} else {
|
||||
symbology_modifier = 4;
|
||||
}
|
||||
} else {
|
||||
if fnc1_positions.contains(0) || fnc1_positions.contains(4) {
|
||||
symbology_modifier = 2;
|
||||
} else if fnc1_positions.contains(1) || fnc1_positions.contains(5) {
|
||||
symbology_modifier = 3;
|
||||
} else {
|
||||
symbology_modifier = 1;
|
||||
}
|
||||
}
|
||||
return Ok(DecoderResult::new(&bytes, &result.to_string(), if byte_segments.is_empty() { null } else { byte_segments }, null, symbology_modifier));
|
||||
}
|
||||
|
||||
/**
|
||||
* See ISO 16022:2006, 5.2.3 and Annex C, Table C.2
|
||||
*/
|
||||
fn decode_ascii_segment( bits: &BitSource, result: &ECIStringBuilder, result_trailer: &StringBuilder, fnc1positions: &Set<Integer>) -> /* throws FormatException */Result<Mode, Rc<Exception>> {
|
||||
let upper_shift: bool = false;
|
||||
loop { {
|
||||
let one_byte: i32 = bits.read_bits(8);
|
||||
if one_byte == 0 {
|
||||
throw FormatException::get_format_instance();
|
||||
} else if one_byte <= 128 {
|
||||
// ASCII data (ASCII value + 1)
|
||||
if upper_shift {
|
||||
one_byte += 128;
|
||||
//upperShift = false;
|
||||
}
|
||||
result.append((one_byte - 1) as char);
|
||||
return Ok(Mode::ASCII_ENCODE);
|
||||
} else if one_byte == 129 {
|
||||
// Pad
|
||||
return Ok(Mode::PAD_ENCODE);
|
||||
} else if one_byte <= 229 {
|
||||
// 2-digit data 00-99 (Numeric Value + 130)
|
||||
let value: i32 = one_byte - 130;
|
||||
if value < 10 {
|
||||
// pad with '0' for single digit values
|
||||
result.append('0');
|
||||
}
|
||||
result.append(value);
|
||||
} else {
|
||||
match one_byte {
|
||||
// Latch to C40 encodation
|
||||
230 =>
|
||||
{
|
||||
return Ok(Mode::C40_ENCODE);
|
||||
}
|
||||
// Latch to Base 256 encodation
|
||||
231 =>
|
||||
{
|
||||
return Ok(Mode::BASE256_ENCODE);
|
||||
}
|
||||
// FNC1
|
||||
232 =>
|
||||
{
|
||||
fnc1positions.add(&result.length());
|
||||
// translate as ASCII 29
|
||||
result.append(29 as char);
|
||||
break;
|
||||
}
|
||||
// Structured Append
|
||||
233 =>
|
||||
{
|
||||
}
|
||||
// Reader Programming
|
||||
234 =>
|
||||
{
|
||||
//throw ReaderException.getInstance();
|
||||
break;
|
||||
}
|
||||
// Upper Shift (shift to Extended ASCII)
|
||||
235 =>
|
||||
{
|
||||
upper_shift = true;
|
||||
break;
|
||||
}
|
||||
// 05 Macro
|
||||
236 =>
|
||||
{
|
||||
result.append("[)>05");
|
||||
result_trailer.insert(0, "");
|
||||
break;
|
||||
}
|
||||
// 06 Macro
|
||||
237 =>
|
||||
{
|
||||
result.append("[)>06");
|
||||
result_trailer.insert(0, "");
|
||||
break;
|
||||
}
|
||||
// Latch to ANSI X12 encodation
|
||||
238 =>
|
||||
{
|
||||
return Ok(Mode::ANSIX12_ENCODE);
|
||||
}
|
||||
// Latch to Text encodation
|
||||
239 =>
|
||||
{
|
||||
return Ok(Mode::TEXT_ENCODE);
|
||||
}
|
||||
// Latch to EDIFACT encodation
|
||||
240 =>
|
||||
{
|
||||
return Ok(Mode::EDIFACT_ENCODE);
|
||||
}
|
||||
// ECI Character
|
||||
241 =>
|
||||
{
|
||||
return Ok(Mode::ECI_ENCODE);
|
||||
}
|
||||
_ =>
|
||||
{
|
||||
// but work around encoders that end with 254, latch back to ASCII
|
||||
if one_byte != 254 || bits.available() != 0 {
|
||||
throw FormatException::get_format_instance();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}if !(bits.available() > 0) break;}
|
||||
return Ok(Mode::ASCII_ENCODE);
|
||||
}
|
||||
|
||||
/**
|
||||
* See ISO 16022:2006, 5.2.5 and Annex C, Table C.1
|
||||
*/
|
||||
fn decode_c40_segment( bits: &BitSource, result: &ECIStringBuilder, fnc1positions: &Set<Integer>) -> /* throws FormatException */Result<Void, Rc<Exception>> {
|
||||
// Three C40 values are encoded in a 16-bit value as
|
||||
// (1600 * C1) + (40 * C2) + C3 + 1
|
||||
// TODO(bbrown): The Upper Shift with C40 doesn't work in the 4 value scenario all the time
|
||||
let upper_shift: bool = false;
|
||||
let c_values: [i32; 3] = [0; 3];
|
||||
let mut shift: i32 = 0;
|
||||
loop { {
|
||||
// If there is only one byte left then it will be encoded as ASCII
|
||||
if bits.available() == 8 {
|
||||
return;
|
||||
}
|
||||
let first_byte: i32 = bits.read_bits(8);
|
||||
if first_byte == 254 {
|
||||
// Unlatch codeword
|
||||
return;
|
||||
}
|
||||
::parse_two_bytes(first_byte, &bits.read_bits(8), &c_values);
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < 3 {
|
||||
{
|
||||
let c_value: i32 = c_values[i];
|
||||
match shift {
|
||||
0 =>
|
||||
{
|
||||
if c_value < 3 {
|
||||
shift = c_value + 1;
|
||||
} else if c_value < C40_BASIC_SET_CHARS.len() {
|
||||
let c40char: char = C40_BASIC_SET_CHARS[c_value];
|
||||
if upper_shift {
|
||||
result.append((c40char + 128) as char);
|
||||
upper_shift = false;
|
||||
} else {
|
||||
result.append(c40char);
|
||||
}
|
||||
} else {
|
||||
throw FormatException::get_format_instance();
|
||||
}
|
||||
break;
|
||||
}
|
||||
1 =>
|
||||
{
|
||||
if upper_shift {
|
||||
result.append((c_value + 128) as char);
|
||||
upper_shift = false;
|
||||
} else {
|
||||
result.append(c_value as char);
|
||||
}
|
||||
shift = 0;
|
||||
break;
|
||||
}
|
||||
2 =>
|
||||
{
|
||||
if c_value < C40_SHIFT2_SET_CHARS.len() {
|
||||
let c40char: char = C40_SHIFT2_SET_CHARS[c_value];
|
||||
if upper_shift {
|
||||
result.append((c40char + 128) as char);
|
||||
upper_shift = false;
|
||||
} else {
|
||||
result.append(c40char);
|
||||
}
|
||||
} else {
|
||||
match c_value {
|
||||
// FNC1
|
||||
27 =>
|
||||
{
|
||||
fnc1positions.add(&result.length());
|
||||
// translate as ASCII 29
|
||||
result.append(29 as char);
|
||||
break;
|
||||
}
|
||||
// Upper Shift
|
||||
30 =>
|
||||
{
|
||||
upper_shift = true;
|
||||
break;
|
||||
}
|
||||
_ =>
|
||||
{
|
||||
throw FormatException::get_format_instance();
|
||||
}
|
||||
}
|
||||
}
|
||||
shift = 0;
|
||||
break;
|
||||
}
|
||||
3 =>
|
||||
{
|
||||
if upper_shift {
|
||||
result.append((c_value + 224) as char);
|
||||
upper_shift = false;
|
||||
} else {
|
||||
result.append((c_value + 96) as char);
|
||||
}
|
||||
shift = 0;
|
||||
break;
|
||||
}
|
||||
_ =>
|
||||
{
|
||||
throw FormatException::get_format_instance();
|
||||
}
|
||||
}
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
}if !(bits.available() > 0) break;}
|
||||
}
|
||||
|
||||
/**
|
||||
* See ISO 16022:2006, 5.2.6 and Annex C, Table C.2
|
||||
*/
|
||||
fn decode_text_segment( bits: &BitSource, result: &ECIStringBuilder, fnc1positions: &Set<Integer>) -> /* throws FormatException */Result<Void, Rc<Exception>> {
|
||||
// Three Text values are encoded in a 16-bit value as
|
||||
// (1600 * C1) + (40 * C2) + C3 + 1
|
||||
// TODO(bbrown): The Upper Shift with Text doesn't work in the 4 value scenario all the time
|
||||
let upper_shift: bool = false;
|
||||
let c_values: [i32; 3] = [0; 3];
|
||||
let mut shift: i32 = 0;
|
||||
loop { {
|
||||
// If there is only one byte left then it will be encoded as ASCII
|
||||
if bits.available() == 8 {
|
||||
return;
|
||||
}
|
||||
let first_byte: i32 = bits.read_bits(8);
|
||||
if first_byte == 254 {
|
||||
// Unlatch codeword
|
||||
return;
|
||||
}
|
||||
::parse_two_bytes(first_byte, &bits.read_bits(8), &c_values);
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < 3 {
|
||||
{
|
||||
let c_value: i32 = c_values[i];
|
||||
match shift {
|
||||
0 =>
|
||||
{
|
||||
if c_value < 3 {
|
||||
shift = c_value + 1;
|
||||
} else if c_value < TEXT_BASIC_SET_CHARS.len() {
|
||||
let text_char: char = TEXT_BASIC_SET_CHARS[c_value];
|
||||
if upper_shift {
|
||||
result.append((text_char + 128) as char);
|
||||
upper_shift = false;
|
||||
} else {
|
||||
result.append(text_char);
|
||||
}
|
||||
} else {
|
||||
throw FormatException::get_format_instance();
|
||||
}
|
||||
break;
|
||||
}
|
||||
1 =>
|
||||
{
|
||||
if upper_shift {
|
||||
result.append((c_value + 128) as char);
|
||||
upper_shift = false;
|
||||
} else {
|
||||
result.append(c_value as char);
|
||||
}
|
||||
shift = 0;
|
||||
break;
|
||||
}
|
||||
2 =>
|
||||
{
|
||||
// Shift 2 for Text is the same encoding as C40
|
||||
if c_value < TEXT_SHIFT2_SET_CHARS.len() {
|
||||
let text_char: char = TEXT_SHIFT2_SET_CHARS[c_value];
|
||||
if upper_shift {
|
||||
result.append((text_char + 128) as char);
|
||||
upper_shift = false;
|
||||
} else {
|
||||
result.append(text_char);
|
||||
}
|
||||
} else {
|
||||
match c_value {
|
||||
// FNC1
|
||||
27 =>
|
||||
{
|
||||
fnc1positions.add(&result.length());
|
||||
// translate as ASCII 29
|
||||
result.append(29 as char);
|
||||
break;
|
||||
}
|
||||
// Upper Shift
|
||||
30 =>
|
||||
{
|
||||
upper_shift = true;
|
||||
break;
|
||||
}
|
||||
_ =>
|
||||
{
|
||||
throw FormatException::get_format_instance();
|
||||
}
|
||||
}
|
||||
}
|
||||
shift = 0;
|
||||
break;
|
||||
}
|
||||
3 =>
|
||||
{
|
||||
if c_value < TEXT_SHIFT3_SET_CHARS.len() {
|
||||
let text_char: char = TEXT_SHIFT3_SET_CHARS[c_value];
|
||||
if upper_shift {
|
||||
result.append((text_char + 128) as char);
|
||||
upper_shift = false;
|
||||
} else {
|
||||
result.append(text_char);
|
||||
}
|
||||
shift = 0;
|
||||
} else {
|
||||
throw FormatException::get_format_instance();
|
||||
}
|
||||
break;
|
||||
}
|
||||
_ =>
|
||||
{
|
||||
throw FormatException::get_format_instance();
|
||||
}
|
||||
}
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
}if !(bits.available() > 0) break;}
|
||||
}
|
||||
|
||||
/**
|
||||
* See ISO 16022:2006, 5.2.7
|
||||
*/
|
||||
fn decode_ansi_x12_segment( bits: &BitSource, result: &ECIStringBuilder) -> /* throws FormatException */Result<Void, Rc<Exception>> {
|
||||
// Three ANSI X12 values are encoded in a 16-bit value as
|
||||
// (1600 * C1) + (40 * C2) + C3 + 1
|
||||
let c_values: [i32; 3] = [0; 3];
|
||||
loop { {
|
||||
// If there is only one byte left then it will be encoded as ASCII
|
||||
if bits.available() == 8 {
|
||||
return;
|
||||
}
|
||||
let first_byte: i32 = bits.read_bits(8);
|
||||
if first_byte == 254 {
|
||||
// Unlatch codeword
|
||||
return;
|
||||
}
|
||||
::parse_two_bytes(first_byte, &bits.read_bits(8), &c_values);
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < 3 {
|
||||
{
|
||||
let c_value: i32 = c_values[i];
|
||||
match c_value {
|
||||
// X12 segment terminator <CR>
|
||||
0 =>
|
||||
{
|
||||
result.append('\r');
|
||||
break;
|
||||
}
|
||||
// X12 segment separator *
|
||||
1 =>
|
||||
{
|
||||
result.append('*');
|
||||
break;
|
||||
}
|
||||
// X12 sub-element separator >
|
||||
2 =>
|
||||
{
|
||||
result.append('>');
|
||||
break;
|
||||
}
|
||||
// space
|
||||
3 =>
|
||||
{
|
||||
result.append(' ');
|
||||
break;
|
||||
}
|
||||
_ =>
|
||||
{
|
||||
if c_value < 14 {
|
||||
// 0 - 9
|
||||
result.append((c_value + 44) as char);
|
||||
} else if c_value < 40 {
|
||||
// A - Z
|
||||
result.append((c_value + 51) as char);
|
||||
} else {
|
||||
throw FormatException::get_format_instance();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
}if !(bits.available() > 0) break;}
|
||||
}
|
||||
|
||||
fn parse_two_bytes( first_byte: i32, second_byte: i32, result: &Vec<i32>) {
|
||||
let full_bit_value: i32 = (first_byte << 8) + second_byte - 1;
|
||||
let mut temp: i32 = full_bit_value / 1600;
|
||||
result[0] = temp;
|
||||
full_bit_value -= temp * 1600;
|
||||
temp = full_bit_value / 40;
|
||||
result[1] = temp;
|
||||
result[2] = full_bit_value - temp * 40;
|
||||
}
|
||||
|
||||
/**
|
||||
* See ISO 16022:2006, 5.2.8 and Annex C Table C.3
|
||||
*/
|
||||
fn decode_edifact_segment( bits: &BitSource, result: &ECIStringBuilder) {
|
||||
loop { {
|
||||
// If there is only two or less bytes left then it will be encoded as ASCII
|
||||
if bits.available() <= 16 {
|
||||
return;
|
||||
}
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < 4 {
|
||||
{
|
||||
let edifact_value: i32 = bits.read_bits(6);
|
||||
// Check for the unlatch character
|
||||
if edifact_value == 0x1F {
|
||||
// 011111
|
||||
// Read rest of byte, which should be 0, and stop
|
||||
let bits_left: i32 = 8 - bits.get_bit_offset();
|
||||
if bits_left != 8 {
|
||||
bits.read_bits(bits_left);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (edifact_value & 0x20) == 0 {
|
||||
// no 1 in the leading (6th) bit
|
||||
// Add a leading 01 to the 6 bit binary value
|
||||
edifact_value |= 0x40;
|
||||
}
|
||||
result.append(edifact_value as char);
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
}if !(bits.available() > 0) break;}
|
||||
}
|
||||
|
||||
/**
|
||||
* See ISO 16022:2006, 5.2.9 and Annex B, B.2
|
||||
*/
|
||||
fn decode_base256_segment( bits: &BitSource, result: &ECIStringBuilder, byte_segments: &Collection<Vec<i8>>) -> /* throws FormatException */Result<Void, Rc<Exception>> {
|
||||
// Figure out how long the Base 256 Segment is.
|
||||
// position is 1-indexed
|
||||
let codeword_position: i32 = 1 + bits.get_byte_offset();
|
||||
let d1: i32 = ::unrandomize255_state(&bits.read_bits(8), codeword_position += 1 !!!check!!! post increment);
|
||||
let mut count: i32;
|
||||
if d1 == 0 {
|
||||
// Read the remainder of the symbol
|
||||
count = bits.available() / 8;
|
||||
} else if d1 < 250 {
|
||||
count = d1;
|
||||
} else {
|
||||
count = 250 * (d1 - 249) + ::unrandomize255_state(&bits.read_bits(8), codeword_position += 1 !!!check!!! post increment);
|
||||
}
|
||||
// We're seeing NegativeArraySizeException errors from users.
|
||||
if count < 0 {
|
||||
throw FormatException::get_format_instance();
|
||||
}
|
||||
let mut bytes: [i8; count] = [0; count];
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < count {
|
||||
{
|
||||
// http://www.bcgen.com/demo/IDAutomationStreamingDataMatrix.aspx?MODE=3&D=Fred&PFMT=3&PT=F&X=0.3&O=0&LM=0.2
|
||||
if bits.available() < 8 {
|
||||
throw FormatException::get_format_instance();
|
||||
}
|
||||
bytes[i] = ::unrandomize255_state(&bits.read_bits(8), codeword_position += 1 !!!check!!! post increment) as i8;
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
byte_segments.add(&bytes);
|
||||
result.append(String::new(&bytes, StandardCharsets::ISO_8859_1));
|
||||
}
|
||||
|
||||
/**
|
||||
* See ISO 16022:2007, 5.4.1
|
||||
*/
|
||||
fn decode_e_c_i_segment( bits: &BitSource, result: &ECIStringBuilder) -> /* throws FormatException */Result<Void, Rc<Exception>> {
|
||||
if bits.available() < 8 {
|
||||
throw FormatException::get_format_instance();
|
||||
}
|
||||
let c1: i32 = bits.read_bits(8);
|
||||
if c1 <= 127 {
|
||||
result.append_e_c_i(c1 - 1);
|
||||
}
|
||||
//currently we only support character set ECIs
|
||||
/*} else {
|
||||
if (bits.available() < 8) {
|
||||
throw FormatException.getFormatInstance();
|
||||
}
|
||||
int c2 = bits.readBits(8);
|
||||
if (c1 >= 128 && c1 <= 191) {
|
||||
} else {
|
||||
if (bits.available() < 8) {
|
||||
throw FormatException.getFormatInstance();
|
||||
}
|
||||
int c3 = bits.readBits(8);
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
/**
|
||||
* See ISO 16022:2006, Annex B, B.2
|
||||
*/
|
||||
fn unrandomize255_state( randomized_base256_codeword: i32, base256_codeword_position: i32) -> i32 {
|
||||
let pseudo_random_number: i32 = ((149 * base256_codeword_position) % 255) + 1;
|
||||
let temp_variable: i32 = randomized_base256_codeword - pseudo_random_number;
|
||||
return if temp_variable >= 0 { temp_variable } else { temp_variable + 256 };
|
||||
}
|
||||
}
|
||||
|
||||
149
port_src/output/zxing/datamatrix/decoder/decoder.rs
Normal file
149
port_src/output/zxing/datamatrix/decoder/decoder.rs
Normal file
@@ -0,0 +1,149 @@
|
||||
/*
|
||||
* 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::datamatrix::decoder;
|
||||
|
||||
/**
|
||||
* <p>The main class which implements Data Matrix Code decoding -- as opposed to locating and extracting
|
||||
* the Data Matrix Code from an image.</p>
|
||||
*
|
||||
* @author bbrown@google.com (Brian Brown)
|
||||
*/
|
||||
pub struct Decoder {
|
||||
|
||||
let rs_decoder: ReedSolomonDecoder;
|
||||
}
|
||||
|
||||
impl Decoder {
|
||||
|
||||
pub fn new() -> Decoder {
|
||||
rs_decoder = ReedSolomonDecoder::new(GenericGF::DATA_MATRIX_FIELD_256);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Convenience method that can decode a Data Matrix Code represented as a 2D array of booleans.
|
||||
* "true" is taken to mean a black module.</p>
|
||||
*
|
||||
* @param image booleans representing white/black Data Matrix Code modules
|
||||
* @return text and bytes encoded within the Data Matrix Code
|
||||
* @throws FormatException if the Data Matrix Code cannot be decoded
|
||||
* @throws ChecksumException if error correction fails
|
||||
*/
|
||||
pub fn decode(&self, image: &Vec<Vec<bool>>) -> /* throws FormatException, ChecksumException */Result<DecoderResult, Rc<Exception>> {
|
||||
return Ok(self.decode(&BitMatrix::parse(&image)));
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Decodes a Data Matrix Code represented as a {@link BitMatrix}. A 1 or "true" is taken
|
||||
* to mean a black module.</p>
|
||||
*
|
||||
* @param bits booleans representing white/black Data Matrix Code modules
|
||||
* @return text and bytes encoded within the Data Matrix Code
|
||||
* @throws FormatException if the Data Matrix Code cannot be decoded
|
||||
* @throws ChecksumException if error correction fails
|
||||
*/
|
||||
pub fn decode(&self, bits: &BitMatrix) -> /* throws FormatException, ChecksumException */Result<DecoderResult, Rc<Exception>> {
|
||||
// Construct a parser and read version, error-correction level
|
||||
let parser: BitMatrixParser = BitMatrixParser::new(bits);
|
||||
let version: Version = parser.get_version();
|
||||
// Read codewords
|
||||
let codewords: Vec<i8> = parser.read_codewords();
|
||||
// Separate into data blocks
|
||||
let data_blocks: Vec<DataBlock> = DataBlock::get_data_blocks(&codewords, version);
|
||||
// Count total number of data bytes
|
||||
let total_bytes: i32 = 0;
|
||||
for let db: DataBlock in data_blocks {
|
||||
total_bytes += db.get_num_data_codewords();
|
||||
}
|
||||
let result_bytes: [i8; total_bytes] = [0; total_bytes];
|
||||
let data_blocks_count: i32 = data_blocks.len();
|
||||
// Error-correct and copy data blocks together into a stream of bytes
|
||||
{
|
||||
let mut j: i32 = 0;
|
||||
while j < data_blocks_count {
|
||||
{
|
||||
let data_block: DataBlock = data_blocks[j];
|
||||
let codeword_bytes: Vec<i8> = data_block.get_codewords();
|
||||
let num_data_codewords: i32 = data_block.get_num_data_codewords();
|
||||
self.correct_errors(&codeword_bytes, num_data_codewords);
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < num_data_codewords {
|
||||
{
|
||||
// De-interlace data blocks.
|
||||
result_bytes[i * data_blocks_count + j] = codeword_bytes[i];
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
j += 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Decode the contents of that stream of bytes
|
||||
return Ok(DecodedBitStreamParser::decode(&result_bytes));
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Given data and error-correction codewords received, possibly corrupted by errors, attempts to
|
||||
* correct the errors in-place using Reed-Solomon error correction.</p>
|
||||
*
|
||||
* @param codewordBytes data and error correction codewords
|
||||
* @param numDataCodewords number of codewords that are data bytes
|
||||
* @throws ChecksumException if error correction fails
|
||||
*/
|
||||
fn correct_errors(&self, codeword_bytes: &Vec<i8>, num_data_codewords: i32) -> /* throws ChecksumException */Result<Void, Rc<Exception>> {
|
||||
let num_codewords: i32 = codeword_bytes.len();
|
||||
// First read into an array of ints
|
||||
let codewords_ints: [i32; num_codewords] = [0; num_codewords];
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < num_codewords {
|
||||
{
|
||||
codewords_ints[i] = codeword_bytes[i] & 0xFF;
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
let tryResult1 = 0;
|
||||
'try1: loop {
|
||||
{
|
||||
self.rs_decoder.decode(&codewords_ints, codeword_bytes.len() - num_data_codewords);
|
||||
}
|
||||
break 'try1
|
||||
}
|
||||
match tryResult1 {
|
||||
catch ( ignored: &ReedSolomonException) {
|
||||
throw ChecksumException::get_checksum_instance();
|
||||
} 0 => break
|
||||
}
|
||||
|
||||
// We don't care about errors in the error-correction codewords
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < num_data_codewords {
|
||||
{
|
||||
codeword_bytes[i] = codewords_ints[i] as i8;
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
189
port_src/output/zxing/datamatrix/decoder/version.rs
Normal file
189
port_src/output/zxing/datamatrix/decoder/version.rs
Normal file
@@ -0,0 +1,189 @@
|
||||
/*
|
||||
* 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::datamatrix::decoder;
|
||||
|
||||
/**
|
||||
* The Version object encapsulates attributes about a particular
|
||||
* size Data Matrix Code.
|
||||
*
|
||||
* @author bbrown@google.com (Brian Brown)
|
||||
*/
|
||||
|
||||
const VERSIONS: Vec<Version> = ::build_versions();
|
||||
pub struct Version {
|
||||
|
||||
let version_number: i32;
|
||||
|
||||
let symbol_size_rows: i32;
|
||||
|
||||
let symbol_size_columns: i32;
|
||||
|
||||
let data_region_size_rows: i32;
|
||||
|
||||
let data_region_size_columns: i32;
|
||||
|
||||
let ec_blocks: ECBlocks;
|
||||
|
||||
let total_codewords: i32;
|
||||
}
|
||||
|
||||
impl Version {
|
||||
|
||||
fn new( version_number: i32, symbol_size_rows: i32, symbol_size_columns: i32, data_region_size_rows: i32, data_region_size_columns: i32, ec_blocks: &ECBlocks) -> Version {
|
||||
let .versionNumber = version_number;
|
||||
let .symbolSizeRows = symbol_size_rows;
|
||||
let .symbolSizeColumns = symbol_size_columns;
|
||||
let .dataRegionSizeRows = data_region_size_rows;
|
||||
let .dataRegionSizeColumns = data_region_size_columns;
|
||||
let .ecBlocks = ec_blocks;
|
||||
// Calculate the total number of codewords
|
||||
let mut total: i32 = 0;
|
||||
let ec_codewords: i32 = ec_blocks.get_e_c_codewords();
|
||||
let ecb_array: Vec<ECB> = ec_blocks.get_e_c_blocks();
|
||||
for let ec_block: ECB in ecb_array {
|
||||
total += ec_block.get_count() * (ec_block.get_data_codewords() + ec_codewords);
|
||||
}
|
||||
let .totalCodewords = total;
|
||||
}
|
||||
|
||||
pub fn get_version_number(&self) -> i32 {
|
||||
return self.version_number;
|
||||
}
|
||||
|
||||
pub fn get_symbol_size_rows(&self) -> i32 {
|
||||
return self.symbol_size_rows;
|
||||
}
|
||||
|
||||
pub fn get_symbol_size_columns(&self) -> i32 {
|
||||
return self.symbol_size_columns;
|
||||
}
|
||||
|
||||
pub fn get_data_region_size_rows(&self) -> i32 {
|
||||
return self.data_region_size_rows;
|
||||
}
|
||||
|
||||
pub fn get_data_region_size_columns(&self) -> i32 {
|
||||
return self.data_region_size_columns;
|
||||
}
|
||||
|
||||
pub fn get_total_codewords(&self) -> i32 {
|
||||
return self.total_codewords;
|
||||
}
|
||||
|
||||
fn get_e_c_blocks(&self) -> ECBlocks {
|
||||
return self.ec_blocks;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Deduces version information from Data Matrix dimensions.</p>
|
||||
*
|
||||
* @param numRows Number of rows in modules
|
||||
* @param numColumns Number of columns in modules
|
||||
* @return Version for a Data Matrix Code of those dimensions
|
||||
* @throws FormatException if dimensions do correspond to a valid Data Matrix size
|
||||
*/
|
||||
pub fn get_version_for_dimensions( num_rows: i32, num_columns: i32) -> /* throws FormatException */Result<Version, Rc<Exception>> {
|
||||
if (num_rows & 0x01) != 0 || (num_columns & 0x01) != 0 {
|
||||
throw FormatException::get_format_instance();
|
||||
}
|
||||
for let version: Version in VERSIONS {
|
||||
if version.symbolSizeRows == num_rows && version.symbolSizeColumns == num_columns {
|
||||
return Ok(version);
|
||||
}
|
||||
}
|
||||
throw FormatException::get_format_instance();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Encapsulates a set of error-correction blocks in one symbol version. Most versions will
|
||||
* use blocks of differing sizes within one version, so, this encapsulates the parameters for
|
||||
* each set of blocks. It also holds the number of error-correction codewords per block since it
|
||||
* will be the same across all blocks within one version.</p>
|
||||
*/
|
||||
struct ECBlocks {
|
||||
|
||||
let ec_codewords: i32;
|
||||
|
||||
let ec_blocks: Vec<ECB>;
|
||||
}
|
||||
|
||||
impl ECBlocks {
|
||||
|
||||
fn new( ec_codewords: i32, ec_blocks: &ECB) -> ECBlocks {
|
||||
let .ecCodewords = ec_codewords;
|
||||
let .ecBlocks = : vec![ECB; 1] = vec![ec_blocks, ]
|
||||
;
|
||||
}
|
||||
|
||||
fn new( ec_codewords: i32, ec_blocks1: &ECB, ec_blocks2: &ECB) -> ECBlocks {
|
||||
let .ecCodewords = ec_codewords;
|
||||
let .ecBlocks = : vec![ECB; 2] = vec![ec_blocks1, ec_blocks2, ]
|
||||
;
|
||||
}
|
||||
|
||||
fn get_e_c_codewords(&self) -> i32 {
|
||||
return self.ec_codewords;
|
||||
}
|
||||
|
||||
fn get_e_c_blocks(&self) -> Vec<ECB> {
|
||||
return self.ec_blocks;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* <p>Encapsulates the parameters for one error-correction block in one symbol version.
|
||||
* This includes the number of data codewords, and the number of times a block with these
|
||||
* parameters is used consecutively in the Data Matrix code version's format.</p>
|
||||
*/
|
||||
struct ECB {
|
||||
|
||||
let count: i32;
|
||||
|
||||
let data_codewords: i32;
|
||||
}
|
||||
|
||||
impl ECB {
|
||||
|
||||
fn new( count: i32, data_codewords: i32) -> ECB {
|
||||
let .count = count;
|
||||
let .dataCodewords = data_codewords;
|
||||
}
|
||||
|
||||
fn get_count(&self) -> i32 {
|
||||
return self.count;
|
||||
}
|
||||
|
||||
fn get_data_codewords(&self) -> i32 {
|
||||
return self.data_codewords;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub fn to_string(&self) -> String {
|
||||
return String::value_of(self.version_number);
|
||||
}
|
||||
|
||||
/**
|
||||
* See ISO 16022:2006 5.5.1 Table 7
|
||||
*/
|
||||
fn build_versions() -> Vec<Version> {
|
||||
return : vec![Version; 48] = vec![Version::new(1, 10, 10, 8, 8, ECBlocks::new(5, ECB::new(1, 3))), Version::new(2, 12, 12, 10, 10, ECBlocks::new(7, ECB::new(1, 5))), Version::new(3, 14, 14, 12, 12, ECBlocks::new(10, ECB::new(1, 8))), Version::new(4, 16, 16, 14, 14, ECBlocks::new(12, ECB::new(1, 12))), Version::new(5, 18, 18, 16, 16, ECBlocks::new(14, ECB::new(1, 18))), Version::new(6, 20, 20, 18, 18, ECBlocks::new(18, ECB::new(1, 22))), Version::new(7, 22, 22, 20, 20, ECBlocks::new(20, ECB::new(1, 30))), Version::new(8, 24, 24, 22, 22, ECBlocks::new(24, ECB::new(1, 36))), Version::new(9, 26, 26, 24, 24, ECBlocks::new(28, ECB::new(1, 44))), Version::new(10, 32, 32, 14, 14, ECBlocks::new(36, ECB::new(1, 62))), Version::new(11, 36, 36, 16, 16, ECBlocks::new(42, ECB::new(1, 86))), Version::new(12, 40, 40, 18, 18, ECBlocks::new(48, ECB::new(1, 114))), Version::new(13, 44, 44, 20, 20, ECBlocks::new(56, ECB::new(1, 144))), Version::new(14, 48, 48, 22, 22, ECBlocks::new(68, ECB::new(1, 174))), Version::new(15, 52, 52, 24, 24, ECBlocks::new(42, ECB::new(2, 102))), Version::new(16, 64, 64, 14, 14, ECBlocks::new(56, ECB::new(2, 140))), Version::new(17, 72, 72, 16, 16, ECBlocks::new(36, ECB::new(4, 92))), Version::new(18, 80, 80, 18, 18, ECBlocks::new(48, ECB::new(4, 114))), Version::new(19, 88, 88, 20, 20, ECBlocks::new(56, ECB::new(4, 144))), Version::new(20, 96, 96, 22, 22, ECBlocks::new(68, ECB::new(4, 174))), Version::new(21, 104, 104, 24, 24, ECBlocks::new(56, ECB::new(6, 136))), Version::new(22, 120, 120, 18, 18, ECBlocks::new(68, ECB::new(6, 175))), Version::new(23, 132, 132, 20, 20, ECBlocks::new(62, ECB::new(8, 163))), Version::new(24, 144, 144, 22, 22, ECBlocks::new(62, ECB::new(8, 156), ECB::new(2, 155))), Version::new(25, 8, 18, 6, 16, ECBlocks::new(7, ECB::new(1, 5))), Version::new(26, 8, 32, 6, 14, ECBlocks::new(11, ECB::new(1, 10))), Version::new(27, 12, 26, 10, 24, ECBlocks::new(14, ECB::new(1, 16))), Version::new(28, 12, 36, 10, 16, ECBlocks::new(18, ECB::new(1, 22))), Version::new(29, 16, 36, 14, 16, ECBlocks::new(24, ECB::new(1, 32))), Version::new(30, 16, 48, 14, 22, ECBlocks::new(28, ECB::new(1, 49))), // ISO 21471:2020 (DMRE) 5.5.1 Table 7
|
||||
Version::new(31, 8, 48, 6, 22, ECBlocks::new(15, ECB::new(1, 18))), Version::new(32, 8, 64, 6, 14, ECBlocks::new(18, ECB::new(1, 24))), Version::new(33, 8, 80, 6, 18, ECBlocks::new(22, ECB::new(1, 32))), Version::new(34, 8, 96, 6, 22, ECBlocks::new(28, ECB::new(1, 38))), Version::new(35, 8, 120, 6, 18, ECBlocks::new(32, ECB::new(1, 49))), Version::new(36, 8, 144, 6, 22, ECBlocks::new(36, ECB::new(1, 63))), Version::new(37, 12, 64, 10, 14, ECBlocks::new(27, ECB::new(1, 43))), Version::new(38, 12, 88, 10, 20, ECBlocks::new(36, ECB::new(1, 64))), Version::new(39, 16, 64, 14, 14, ECBlocks::new(36, ECB::new(1, 62))), Version::new(40, 20, 36, 18, 16, ECBlocks::new(28, ECB::new(1, 44))), Version::new(41, 20, 44, 18, 20, ECBlocks::new(34, ECB::new(1, 56))), Version::new(42, 20, 64, 18, 14, ECBlocks::new(42, ECB::new(1, 84))), Version::new(43, 22, 48, 20, 22, ECBlocks::new(38, ECB::new(1, 72))), Version::new(44, 24, 48, 22, 22, ECBlocks::new(41, ECB::new(1, 80))), Version::new(45, 24, 64, 22, 14, ECBlocks::new(46, ECB::new(1, 108))), Version::new(46, 26, 40, 24, 18, ECBlocks::new(38, ECB::new(1, 70))), Version::new(47, 26, 48, 24, 22, ECBlocks::new(42, ECB::new(1, 90))), Version::new(48, 26, 64, 24, 14, ECBlocks::new(50, ECB::new(1, 118))), ]
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
320
port_src/output/zxing/datamatrix/detector/detector.rs
Normal file
320
port_src/output/zxing/datamatrix/detector/detector.rs
Normal file
@@ -0,0 +1,320 @@
|
||||
/*
|
||||
* 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::datamatrix::detector;
|
||||
|
||||
/**
|
||||
* <p>Encapsulates logic that can detect a Data Matrix Code in an image, even if the Data Matrix Code
|
||||
* is rotated or skewed, or partially obscured.</p>
|
||||
*
|
||||
* @author Sean Owen
|
||||
*/
|
||||
pub struct Detector {
|
||||
|
||||
let image: BitMatrix;
|
||||
|
||||
let rectangle_detector: WhiteRectangleDetector;
|
||||
}
|
||||
|
||||
impl Detector {
|
||||
|
||||
pub fn new( image: &BitMatrix) -> Detector throws NotFoundException {
|
||||
let .image = image;
|
||||
rectangle_detector = WhiteRectangleDetector::new(image);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Detects a Data Matrix Code in an image.</p>
|
||||
*
|
||||
* @return {@link DetectorResult} encapsulating results of detecting a Data Matrix Code
|
||||
* @throws NotFoundException if no Data Matrix Code can be found
|
||||
*/
|
||||
pub fn detect(&self) -> /* throws NotFoundException */Result<DetectorResult, Rc<Exception>> {
|
||||
let corner_points: Vec<ResultPoint> = self.rectangle_detector.detect();
|
||||
let mut points: Vec<ResultPoint> = self.detect_solid1(corner_points);
|
||||
points = self.detect_solid2(points);
|
||||
points[3] = self.correct_top_right(points);
|
||||
if points[3] == null {
|
||||
throw NotFoundException::get_not_found_instance();
|
||||
}
|
||||
points = self.shift_to_module_center(points);
|
||||
let top_left: ResultPoint = points[0];
|
||||
let bottom_left: ResultPoint = points[1];
|
||||
let bottom_right: ResultPoint = points[2];
|
||||
let top_right: ResultPoint = points[3];
|
||||
let dimension_top: i32 = self.transitions_between(top_left, top_right) + 1;
|
||||
let dimension_right: i32 = self.transitions_between(bottom_right, top_right) + 1;
|
||||
if (dimension_top & 0x01) == 1 {
|
||||
dimension_top += 1;
|
||||
}
|
||||
if (dimension_right & 0x01) == 1 {
|
||||
dimension_right += 1;
|
||||
}
|
||||
if 4 * dimension_top < 6 * dimension_right && 4 * dimension_right < 6 * dimension_top {
|
||||
// The matrix is square
|
||||
dimension_top = dimension_right = Math::max(dimension_top, dimension_right);
|
||||
}
|
||||
let bits: BitMatrix = ::sample_grid(self.image, top_left, bottom_left, bottom_right, top_right, dimension_top, dimension_right);
|
||||
return Ok(DetectorResult::new(bits, : vec![ResultPoint; 4] = vec![top_left, bottom_left, bottom_right, top_right, ]
|
||||
));
|
||||
}
|
||||
|
||||
fn shift_point( point: &ResultPoint, to: &ResultPoint, div: i32) -> ResultPoint {
|
||||
let x: f32 = (to.get_x() - point.get_x()) / (div + 1);
|
||||
let y: f32 = (to.get_y() - point.get_y()) / (div + 1);
|
||||
return ResultPoint::new(point.get_x() + x, point.get_y() + y);
|
||||
}
|
||||
|
||||
fn move_away( point: &ResultPoint, from_x: f32, from_y: f32) -> ResultPoint {
|
||||
let mut x: f32 = point.get_x();
|
||||
let mut y: f32 = point.get_y();
|
||||
if x < from_x {
|
||||
x -= 1.0;
|
||||
} else {
|
||||
x += 1.0;
|
||||
}
|
||||
if y < from_y {
|
||||
y -= 1.0;
|
||||
} else {
|
||||
y += 1.0;
|
||||
}
|
||||
return ResultPoint::new(x, y);
|
||||
}
|
||||
|
||||
/**
|
||||
* Detect a solid side which has minimum transition.
|
||||
*/
|
||||
fn detect_solid1(&self, corner_points: &Vec<ResultPoint>) -> Vec<ResultPoint> {
|
||||
// 0 2
|
||||
// 1 3
|
||||
let point_a: ResultPoint = corner_points[0];
|
||||
let point_b: ResultPoint = corner_points[1];
|
||||
let point_c: ResultPoint = corner_points[3];
|
||||
let point_d: ResultPoint = corner_points[2];
|
||||
let tr_a_b: i32 = self.transitions_between(point_a, point_b);
|
||||
let tr_b_c: i32 = self.transitions_between(point_b, point_c);
|
||||
let tr_c_d: i32 = self.transitions_between(point_c, point_d);
|
||||
let tr_d_a: i32 = self.transitions_between(point_d, point_a);
|
||||
// 0..3
|
||||
// : :
|
||||
// 1--2
|
||||
let mut min: i32 = tr_a_b;
|
||||
let mut points: vec![Vec<ResultPoint>; 4] = vec![point_d, point_a, point_b, point_c, ]
|
||||
;
|
||||
if min > tr_b_c {
|
||||
min = tr_b_c;
|
||||
points[0] = point_a;
|
||||
points[1] = point_b;
|
||||
points[2] = point_c;
|
||||
points[3] = point_d;
|
||||
}
|
||||
if min > tr_c_d {
|
||||
min = tr_c_d;
|
||||
points[0] = point_b;
|
||||
points[1] = point_c;
|
||||
points[2] = point_d;
|
||||
points[3] = point_a;
|
||||
}
|
||||
if min > tr_d_a {
|
||||
points[0] = point_c;
|
||||
points[1] = point_d;
|
||||
points[2] = point_a;
|
||||
points[3] = point_b;
|
||||
}
|
||||
return points;
|
||||
}
|
||||
|
||||
/**
|
||||
* Detect a second solid side next to first solid side.
|
||||
*/
|
||||
fn detect_solid2(&self, points: &Vec<ResultPoint>) -> Vec<ResultPoint> {
|
||||
// A..D
|
||||
// : :
|
||||
// B--C
|
||||
let point_a: ResultPoint = points[0];
|
||||
let point_b: ResultPoint = points[1];
|
||||
let point_c: ResultPoint = points[2];
|
||||
let point_d: ResultPoint = points[3];
|
||||
// Transition detection on the edge is not stable.
|
||||
// To safely detect, shift the points to the module center.
|
||||
let tr: i32 = self.transitions_between(point_a, point_d);
|
||||
let point_bs: ResultPoint = ::shift_point(point_b, point_c, (tr + 1) * 4);
|
||||
let point_cs: ResultPoint = ::shift_point(point_c, point_b, (tr + 1) * 4);
|
||||
let tr_b_a: i32 = self.transitions_between(point_bs, point_a);
|
||||
let tr_c_d: i32 = self.transitions_between(point_cs, point_d);
|
||||
// 1--2
|
||||
if tr_b_a < tr_c_d {
|
||||
// solid sides: A-B-C
|
||||
points[0] = point_a;
|
||||
points[1] = point_b;
|
||||
points[2] = point_c;
|
||||
points[3] = point_d;
|
||||
} else {
|
||||
// solid sides: B-C-D
|
||||
points[0] = point_b;
|
||||
points[1] = point_c;
|
||||
points[2] = point_d;
|
||||
points[3] = point_a;
|
||||
}
|
||||
return points;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the corner position of the white top right module.
|
||||
*/
|
||||
fn correct_top_right(&self, points: &Vec<ResultPoint>) -> ResultPoint {
|
||||
// A..D
|
||||
// | :
|
||||
// B--C
|
||||
let point_a: ResultPoint = points[0];
|
||||
let point_b: ResultPoint = points[1];
|
||||
let point_c: ResultPoint = points[2];
|
||||
let point_d: ResultPoint = points[3];
|
||||
// shift points for safe transition detection.
|
||||
let tr_top: i32 = self.transitions_between(point_a, point_d);
|
||||
let tr_right: i32 = self.transitions_between(point_b, point_d);
|
||||
let point_as: ResultPoint = ::shift_point(point_a, point_b, (tr_right + 1) * 4);
|
||||
let point_cs: ResultPoint = ::shift_point(point_c, point_b, (tr_top + 1) * 4);
|
||||
tr_top = self.transitions_between(point_as, point_d);
|
||||
tr_right = self.transitions_between(point_cs, point_d);
|
||||
let candidate1: ResultPoint = ResultPoint::new(point_d.get_x() + (point_c.get_x() - point_b.get_x()) / (tr_top + 1), point_d.get_y() + (point_c.get_y() - point_b.get_y()) / (tr_top + 1));
|
||||
let candidate2: ResultPoint = ResultPoint::new(point_d.get_x() + (point_a.get_x() - point_b.get_x()) / (tr_right + 1), point_d.get_y() + (point_a.get_y() - point_b.get_y()) / (tr_right + 1));
|
||||
if !self.is_valid(candidate1) {
|
||||
if self.is_valid(candidate2) {
|
||||
return candidate2;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
if !self.is_valid(candidate2) {
|
||||
return candidate1;
|
||||
}
|
||||
let sumc1: i32 = self.transitions_between(point_as, candidate1) + self.transitions_between(point_cs, candidate1);
|
||||
let sumc2: i32 = self.transitions_between(point_as, candidate2) + self.transitions_between(point_cs, candidate2);
|
||||
if sumc1 > sumc2 {
|
||||
return candidate1;
|
||||
} else {
|
||||
return candidate2;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Shift the edge points to the module center.
|
||||
*/
|
||||
fn shift_to_module_center(&self, points: &Vec<ResultPoint>) -> Vec<ResultPoint> {
|
||||
// A..D
|
||||
// | :
|
||||
// B--C
|
||||
let point_a: ResultPoint = points[0];
|
||||
let point_b: ResultPoint = points[1];
|
||||
let point_c: ResultPoint = points[2];
|
||||
let point_d: ResultPoint = points[3];
|
||||
// calculate pseudo dimensions
|
||||
let dim_h: i32 = self.transitions_between(point_a, point_d) + 1;
|
||||
let dim_v: i32 = self.transitions_between(point_c, point_d) + 1;
|
||||
// shift points for safe dimension detection
|
||||
let point_as: ResultPoint = ::shift_point(point_a, point_b, dim_v * 4);
|
||||
let point_cs: ResultPoint = ::shift_point(point_c, point_b, dim_h * 4);
|
||||
// calculate more precise dimensions
|
||||
dim_h = self.transitions_between(point_as, point_d) + 1;
|
||||
dim_v = self.transitions_between(point_cs, point_d) + 1;
|
||||
if (dim_h & 0x01) == 1 {
|
||||
dim_h += 1;
|
||||
}
|
||||
if (dim_v & 0x01) == 1 {
|
||||
dim_v += 1;
|
||||
}
|
||||
// WhiteRectangleDetector returns points inside of the rectangle.
|
||||
// I want points on the edges.
|
||||
let center_x: f32 = (point_a.get_x() + point_b.get_x() + point_c.get_x() + point_d.get_x()) / 4;
|
||||
let center_y: f32 = (point_a.get_y() + point_b.get_y() + point_c.get_y() + point_d.get_y()) / 4;
|
||||
point_a = ::move_away(point_a, center_x, center_y);
|
||||
point_b = ::move_away(point_b, center_x, center_y);
|
||||
point_c = ::move_away(point_c, center_x, center_y);
|
||||
point_d = ::move_away(point_d, center_x, center_y);
|
||||
let point_bs: ResultPoint;
|
||||
let point_ds: ResultPoint;
|
||||
// shift points to the center of each modules
|
||||
point_as = ::shift_point(point_a, point_b, dim_v * 4);
|
||||
point_as = ::shift_point(point_as, point_d, dim_h * 4);
|
||||
point_bs = ::shift_point(point_b, point_a, dim_v * 4);
|
||||
point_bs = ::shift_point(point_bs, point_c, dim_h * 4);
|
||||
point_cs = ::shift_point(point_c, point_d, dim_v * 4);
|
||||
point_cs = ::shift_point(point_cs, point_b, dim_h * 4);
|
||||
point_ds = ::shift_point(point_d, point_c, dim_v * 4);
|
||||
point_ds = ::shift_point(point_ds, point_a, dim_h * 4);
|
||||
return : vec![ResultPoint; 4] = vec![point_as, point_bs, point_cs, point_ds, ]
|
||||
;
|
||||
}
|
||||
|
||||
fn is_valid(&self, p: &ResultPoint) -> bool {
|
||||
return p.get_x() >= 0 && p.get_x() <= self.image.get_width() - 1 && p.get_y() > 0 && p.get_y() <= self.image.get_height() - 1;
|
||||
}
|
||||
|
||||
fn sample_grid( image: &BitMatrix, top_left: &ResultPoint, bottom_left: &ResultPoint, bottom_right: &ResultPoint, top_right: &ResultPoint, dimension_x: i32, dimension_y: i32) -> /* throws NotFoundException */Result<BitMatrix, Rc<Exception>> {
|
||||
let sampler: GridSampler = GridSampler::get_instance();
|
||||
return Ok(sampler.sample_grid(image, dimension_x, dimension_y, 0.5f, 0.5f, dimension_x - 0.5f, 0.5f, dimension_x - 0.5f, dimension_y - 0.5f, 0.5f, dimension_y - 0.5f, &top_left.get_x(), &top_left.get_y(), &top_right.get_x(), &top_right.get_y(), &bottom_right.get_x(), &bottom_right.get_y(), &bottom_left.get_x(), &bottom_left.get_y()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Counts the number of black/white transitions between two points, using something like Bresenham's algorithm.
|
||||
*/
|
||||
fn transitions_between(&self, from: &ResultPoint, to: &ResultPoint) -> i32 {
|
||||
// See QR Code Detector, sizeOfBlackWhiteBlackRun()
|
||||
let from_x: i32 = from.get_x() as i32;
|
||||
let from_y: i32 = from.get_y() as i32;
|
||||
let to_x: i32 = to.get_x() as i32;
|
||||
let to_y: i32 = Math::min(self.image.get_height() - 1, to.get_y() as i32);
|
||||
let steep: bool = Math::abs(to_y - from_y) > Math::abs(to_x - from_x);
|
||||
if steep {
|
||||
let mut temp: i32 = from_x;
|
||||
from_x = from_y;
|
||||
from_y = temp;
|
||||
temp = to_x;
|
||||
to_x = to_y;
|
||||
to_y = temp;
|
||||
}
|
||||
let dx: i32 = Math::abs(to_x - from_x);
|
||||
let dy: i32 = Math::abs(to_y - from_y);
|
||||
let mut error: i32 = -dx / 2;
|
||||
let ystep: i32 = if from_y < to_y { 1 } else { -1 };
|
||||
let xstep: i32 = if from_x < to_x { 1 } else { -1 };
|
||||
let mut transitions: i32 = 0;
|
||||
let in_black: bool = self.image.get( if steep { from_y } else { from_x }, if steep { from_x } else { from_y });
|
||||
{
|
||||
let mut x: i32 = from_x, let mut y: i32 = from_y;
|
||||
while x != to_x {
|
||||
{
|
||||
let is_black: bool = self.image.get( if steep { y } else { x }, if steep { x } else { y });
|
||||
if is_black != in_black {
|
||||
transitions += 1;
|
||||
in_black = is_black;
|
||||
}
|
||||
error += dy;
|
||||
if error > 0 {
|
||||
if y == to_y {
|
||||
break;
|
||||
}
|
||||
y += ystep;
|
||||
error -= dx;
|
||||
}
|
||||
}
|
||||
x += xstep;
|
||||
}
|
||||
}
|
||||
|
||||
return transitions;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* Copyright 2006-2007 Jeremias Maerki.
|
||||
*
|
||||
* 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::datamatrix::encoder;
|
||||
|
||||
#[derive(Encoder)]
|
||||
struct ASCIIEncoder {
|
||||
}
|
||||
|
||||
impl ASCIIEncoder {
|
||||
|
||||
pub fn get_encoding_mode(&self) -> i32 {
|
||||
return HighLevelEncoder::ASCII_ENCODATION;
|
||||
}
|
||||
|
||||
pub fn encode(&self, context: &EncoderContext) {
|
||||
//step B
|
||||
let n: i32 = HighLevelEncoder::determine_consecutive_digit_count(&context.get_message(), context.pos);
|
||||
if n >= 2 {
|
||||
context.write_codeword(&::encode_a_s_c_i_i_digits(&context.get_message().char_at(context.pos), &context.get_message().char_at(context.pos + 1)));
|
||||
context.pos += 2;
|
||||
} else {
|
||||
let c: char = context.get_current_char();
|
||||
let new_mode: i32 = HighLevelEncoder::look_ahead_test(&context.get_message(), context.pos, &self.get_encoding_mode());
|
||||
if new_mode != self.get_encoding_mode() {
|
||||
match new_mode {
|
||||
HighLevelEncoder::BASE256_ENCODATION =>
|
||||
{
|
||||
context.write_codeword(HighLevelEncoder::LATCH_TO_BASE256);
|
||||
context.signal_encoder_change(HighLevelEncoder::BASE256_ENCODATION);
|
||||
return;
|
||||
}
|
||||
HighLevelEncoder::C40_ENCODATION =>
|
||||
{
|
||||
context.write_codeword(HighLevelEncoder::LATCH_TO_C40);
|
||||
context.signal_encoder_change(HighLevelEncoder::C40_ENCODATION);
|
||||
return;
|
||||
}
|
||||
HighLevelEncoder::X12_ENCODATION =>
|
||||
{
|
||||
context.write_codeword(HighLevelEncoder::LATCH_TO_ANSIX12);
|
||||
context.signal_encoder_change(HighLevelEncoder::X12_ENCODATION);
|
||||
break;
|
||||
}
|
||||
HighLevelEncoder::TEXT_ENCODATION =>
|
||||
{
|
||||
context.write_codeword(HighLevelEncoder::LATCH_TO_TEXT);
|
||||
context.signal_encoder_change(HighLevelEncoder::TEXT_ENCODATION);
|
||||
break;
|
||||
}
|
||||
HighLevelEncoder::EDIFACT_ENCODATION =>
|
||||
{
|
||||
context.write_codeword(HighLevelEncoder::LATCH_TO_EDIFACT);
|
||||
context.signal_encoder_change(HighLevelEncoder::EDIFACT_ENCODATION);
|
||||
break;
|
||||
}
|
||||
_ =>
|
||||
{
|
||||
throw IllegalStateException::new(format!("Illegal mode: {}", new_mode));
|
||||
}
|
||||
}
|
||||
} else if HighLevelEncoder::is_extended_a_s_c_i_i(c) {
|
||||
context.write_codeword(HighLevelEncoder::UPPER_SHIFT);
|
||||
context.write_codeword((c - 128 + 1) as char);
|
||||
context.pos += 1;
|
||||
} else {
|
||||
context.write_codeword((c + 1) as char);
|
||||
context.pos += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn encode_a_s_c_i_i_digits( digit1: char, digit2: char) -> char {
|
||||
if HighLevelEncoder::is_digit(digit1) && HighLevelEncoder::is_digit(digit2) {
|
||||
let num: i32 = (digit1 - 48) * 10 + (digit2 - 48);
|
||||
return (num + 130) as char;
|
||||
}
|
||||
throw IllegalArgumentException::new(format!("not digits: {}{}", digit1, digit2));
|
||||
}
|
||||
}
|
||||
|
||||
80
port_src/output/zxing/datamatrix/encoder/base256_encoder.rs
Normal file
80
port_src/output/zxing/datamatrix/encoder/base256_encoder.rs
Normal file
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright 2006-2007 Jeremias Maerki.
|
||||
*
|
||||
* 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::datamatrix::encoder;
|
||||
|
||||
#[derive(Encoder)]
|
||||
struct Base256Encoder {
|
||||
}
|
||||
|
||||
impl Base256Encoder {
|
||||
|
||||
pub fn get_encoding_mode(&self) -> i32 {
|
||||
return HighLevelEncoder::BASE256_ENCODATION;
|
||||
}
|
||||
|
||||
pub fn encode(&self, context: &EncoderContext) {
|
||||
let buffer: StringBuilder = StringBuilder::new();
|
||||
//Initialize length field
|
||||
buffer.append('\0');
|
||||
while context.has_more_characters() {
|
||||
let c: char = context.get_current_char();
|
||||
buffer.append(c);
|
||||
context.pos += 1;
|
||||
let new_mode: i32 = HighLevelEncoder::look_ahead_test(&context.get_message(), context.pos, &self.get_encoding_mode());
|
||||
if new_mode != self.get_encoding_mode() {
|
||||
// Return to ASCII encodation, which will actually handle latch to new mode
|
||||
context.signal_encoder_change(HighLevelEncoder::ASCII_ENCODATION);
|
||||
break;
|
||||
}
|
||||
}
|
||||
let data_count: i32 = buffer.length() - 1;
|
||||
let length_field_size: i32 = 1;
|
||||
let current_size: i32 = context.get_codeword_count() + data_count + length_field_size;
|
||||
context.update_symbol_info(current_size);
|
||||
let must_pad: bool = (context.get_symbol_info().get_data_capacity() - current_size) > 0;
|
||||
if context.has_more_characters() || must_pad {
|
||||
if data_count <= 249 {
|
||||
buffer.set_char_at(0, data_count as char);
|
||||
} else if data_count <= 1555 {
|
||||
buffer.set_char_at(0, ((data_count / 250) + 249) as char);
|
||||
buffer.insert(1, (data_count % 250) as char);
|
||||
} else {
|
||||
throw IllegalStateException::new(format!("Message length not in valid ranges: {}", data_count));
|
||||
}
|
||||
}
|
||||
{
|
||||
let mut i: i32 = 0, let c: i32 = buffer.length();
|
||||
while i < c {
|
||||
{
|
||||
context.write_codeword(&::randomize255_state(&buffer.char_at(i), context.get_codeword_count() + 1));
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fn randomize255_state( ch: char, codeword_position: i32) -> char {
|
||||
let pseudo_random: i32 = ((149 * codeword_position) % 255) + 1;
|
||||
let temp_variable: i32 = ch + pseudo_random;
|
||||
if temp_variable <= 255 {
|
||||
return temp_variable as char;
|
||||
} else {
|
||||
return (temp_variable - 256) as char;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
212
port_src/output/zxing/datamatrix/encoder/c40_encoder.rs
Normal file
212
port_src/output/zxing/datamatrix/encoder/c40_encoder.rs
Normal file
@@ -0,0 +1,212 @@
|
||||
/*
|
||||
* Copyright 2006-2007 Jeremias Maerki.
|
||||
*
|
||||
* 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::datamatrix::encoder;
|
||||
|
||||
#[derive(Encoder)]
|
||||
struct C40Encoder {
|
||||
}
|
||||
|
||||
impl C40Encoder {
|
||||
|
||||
pub fn get_encoding_mode(&self) -> i32 {
|
||||
return HighLevelEncoder::C40_ENCODATION;
|
||||
}
|
||||
|
||||
fn encode_maximal(&self, context: &EncoderContext) {
|
||||
let buffer: StringBuilder = StringBuilder::new();
|
||||
let last_char_size: i32 = 0;
|
||||
let backtrack_start_position: i32 = context.pos;
|
||||
let backtrack_buffer_length: i32 = 0;
|
||||
while context.has_more_characters() {
|
||||
let c: char = context.get_current_char();
|
||||
context.pos += 1;
|
||||
last_char_size = self.encode_char(c, &buffer);
|
||||
if buffer.length() % 3 == 0 {
|
||||
backtrack_start_position = context.pos;
|
||||
backtrack_buffer_length = buffer.length();
|
||||
}
|
||||
}
|
||||
if backtrack_buffer_length != buffer.length() {
|
||||
let unwritten: i32 = (buffer.length() / 3) * 2;
|
||||
// +1 for the latch to C40
|
||||
let cur_codeword_count: i32 = context.get_codeword_count() + unwritten + 1;
|
||||
context.update_symbol_info(cur_codeword_count);
|
||||
let available: i32 = context.get_symbol_info().get_data_capacity() - cur_codeword_count;
|
||||
let rest: i32 = buffer.length() % 3;
|
||||
if (rest == 2 && available != 2) || (rest == 1 && (last_char_size > 3 || available != 1)) {
|
||||
buffer.set_length(backtrack_buffer_length);
|
||||
context.pos = backtrack_start_position;
|
||||
}
|
||||
}
|
||||
if buffer.length() > 0 {
|
||||
context.write_codeword(HighLevelEncoder::LATCH_TO_C40);
|
||||
}
|
||||
self.handle_e_o_d(context, &buffer);
|
||||
}
|
||||
|
||||
pub fn encode(&self, context: &EncoderContext) {
|
||||
//step C
|
||||
let buffer: StringBuilder = StringBuilder::new();
|
||||
while context.has_more_characters() {
|
||||
let c: char = context.get_current_char();
|
||||
context.pos += 1;
|
||||
let last_char_size: i32 = self.encode_char(c, &buffer);
|
||||
let unwritten: i32 = (buffer.length() / 3) * 2;
|
||||
let cur_codeword_count: i32 = context.get_codeword_count() + unwritten;
|
||||
context.update_symbol_info(cur_codeword_count);
|
||||
let available: i32 = context.get_symbol_info().get_data_capacity() - cur_codeword_count;
|
||||
if !context.has_more_characters() {
|
||||
//Avoid having a single C40 value in the last triplet
|
||||
let removed: StringBuilder = StringBuilder::new();
|
||||
if (buffer.length() % 3) == 2 && available != 2 {
|
||||
last_char_size = self.backtrack_one_character(context, &buffer, &removed, last_char_size);
|
||||
}
|
||||
while (buffer.length() % 3) == 1 && (last_char_size > 3 || available != 1) {
|
||||
last_char_size = self.backtrack_one_character(context, &buffer, &removed, last_char_size);
|
||||
}
|
||||
break;
|
||||
}
|
||||
let count: i32 = buffer.length();
|
||||
if (count % 3) == 0 {
|
||||
let new_mode: i32 = HighLevelEncoder::look_ahead_test(&context.get_message(), context.pos, &self.get_encoding_mode());
|
||||
if new_mode != self.get_encoding_mode() {
|
||||
// Return to ASCII encodation, which will actually handle latch to new mode
|
||||
context.signal_encoder_change(HighLevelEncoder::ASCII_ENCODATION);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
self.handle_e_o_d(context, &buffer);
|
||||
}
|
||||
|
||||
fn backtrack_one_character(&self, context: &EncoderContext, buffer: &StringBuilder, removed: &StringBuilder, last_char_size: i32) -> i32 {
|
||||
let count: i32 = buffer.length();
|
||||
buffer.delete(count - last_char_size, count);
|
||||
context.pos -= 1;
|
||||
let c: char = context.get_current_char();
|
||||
last_char_size = self.encode_char(c, &removed);
|
||||
//Deal with possible reduction in symbol size
|
||||
context.reset_symbol_info();
|
||||
return last_char_size;
|
||||
}
|
||||
|
||||
fn write_next_triplet( context: &EncoderContext, buffer: &StringBuilder) {
|
||||
context.write_codewords(&::encode_to_codewords(&buffer));
|
||||
buffer.delete(0, 3);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle "end of data" situations
|
||||
*
|
||||
* @param context the encoder context
|
||||
* @param buffer the buffer with the remaining encoded characters
|
||||
*/
|
||||
fn handle_e_o_d(&self, context: &EncoderContext, buffer: &StringBuilder) {
|
||||
let unwritten: i32 = (buffer.length() / 3) * 2;
|
||||
let rest: i32 = buffer.length() % 3;
|
||||
let cur_codeword_count: i32 = context.get_codeword_count() + unwritten;
|
||||
context.update_symbol_info(cur_codeword_count);
|
||||
let available: i32 = context.get_symbol_info().get_data_capacity() - cur_codeword_count;
|
||||
if rest == 2 {
|
||||
//Shift 1
|
||||
buffer.append('\0');
|
||||
while buffer.length() >= 3 {
|
||||
::write_next_triplet(context, &buffer);
|
||||
}
|
||||
if context.has_more_characters() {
|
||||
context.write_codeword(HighLevelEncoder::C40_UNLATCH);
|
||||
}
|
||||
} else if available == 1 && rest == 1 {
|
||||
while buffer.length() >= 3 {
|
||||
::write_next_triplet(context, &buffer);
|
||||
}
|
||||
if context.has_more_characters() {
|
||||
context.write_codeword(HighLevelEncoder::C40_UNLATCH);
|
||||
}
|
||||
// else no unlatch
|
||||
context.pos -= 1;
|
||||
} else if rest == 0 {
|
||||
while buffer.length() >= 3 {
|
||||
::write_next_triplet(context, &buffer);
|
||||
}
|
||||
if available > 0 || context.has_more_characters() {
|
||||
context.write_codeword(HighLevelEncoder::C40_UNLATCH);
|
||||
}
|
||||
} else {
|
||||
throw IllegalStateException::new("Unexpected case. Please report!");
|
||||
}
|
||||
context.signal_encoder_change(HighLevelEncoder::ASCII_ENCODATION);
|
||||
}
|
||||
|
||||
fn encode_char(&self, c: char, sb: &StringBuilder) -> i32 {
|
||||
if c == ' ' {
|
||||
sb.append('\3');
|
||||
return 1;
|
||||
}
|
||||
if c >= '0' && c <= '9' {
|
||||
sb.append((c - 48 + 4) as char);
|
||||
return 1;
|
||||
}
|
||||
if c >= 'A' && c <= 'Z' {
|
||||
sb.append((c - 65 + 14) as char);
|
||||
return 1;
|
||||
}
|
||||
if c < ' ' {
|
||||
//Shift 1 Set
|
||||
sb.append('\0');
|
||||
sb.append(c);
|
||||
return 2;
|
||||
}
|
||||
if c <= '/' {
|
||||
//Shift 2 Set
|
||||
sb.append('\1');
|
||||
sb.append((c - 33) as char);
|
||||
return 2;
|
||||
}
|
||||
if c <= '@' {
|
||||
//Shift 2 Set
|
||||
sb.append('\1');
|
||||
sb.append((c - 58 + 15) as char);
|
||||
return 2;
|
||||
}
|
||||
if c <= '_' {
|
||||
//Shift 2 Set
|
||||
sb.append('\1');
|
||||
sb.append((c - 91 + 22) as char);
|
||||
return 2;
|
||||
}
|
||||
if c <= 127 {
|
||||
//Shift 3 Set
|
||||
sb.append('\2');
|
||||
sb.append((c - 96) as char);
|
||||
return 2;
|
||||
}
|
||||
//Shift 2, Upper Shift
|
||||
sb.append("\1");
|
||||
let mut len: i32 = 2;
|
||||
len += self.encode_char((c - 128) as char, &sb);
|
||||
return len;
|
||||
}
|
||||
|
||||
fn encode_to_codewords( sb: &CharSequence) -> String {
|
||||
let v: i32 = (1600 * sb.char_at(0)) + (40 * sb.char_at(1)) + sb.char_at(2) + 1;
|
||||
let cw1: char = (v / 256) as char;
|
||||
let cw2: char = (v % 256) as char;
|
||||
return String::new( : vec![char; 2] = vec![cw1, cw2, ]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright 2006 Jeremias Maerki
|
||||
*
|
||||
* 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::datamatrix::encoder;
|
||||
|
||||
struct DataMatrixSymbolInfo144 {
|
||||
super: SymbolInfo;
|
||||
}
|
||||
|
||||
impl DataMatrixSymbolInfo144 {
|
||||
|
||||
fn new() -> DataMatrixSymbolInfo144 {
|
||||
super(false, 1558, 620, 22, 22, 36, -1, 62);
|
||||
}
|
||||
|
||||
pub fn get_interleaved_block_count(&self) -> i32 {
|
||||
return 10;
|
||||
}
|
||||
|
||||
pub fn get_data_length_for_interleaved_block(&self, index: i32) -> i32 {
|
||||
return if (index <= 8) { 156 } else { 155 };
|
||||
}
|
||||
}
|
||||
|
||||
198
port_src/output/zxing/datamatrix/encoder/default_placement.rs
Normal file
198
port_src/output/zxing/datamatrix/encoder/default_placement.rs
Normal file
@@ -0,0 +1,198 @@
|
||||
/*
|
||||
* Copyright 2006 Jeremias Maerki.
|
||||
*
|
||||
* 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::datamatrix::encoder;
|
||||
|
||||
/**
|
||||
* Symbol Character Placement Program. Adapted from Annex M.1 in ISO/IEC 16022:2000(E).
|
||||
*/
|
||||
pub struct DefaultPlacement {
|
||||
|
||||
let codewords: CharSequence;
|
||||
|
||||
let numrows: i32;
|
||||
|
||||
let mut numcols: i32;
|
||||
|
||||
let mut bits: Vec<i8>;
|
||||
}
|
||||
|
||||
impl DefaultPlacement {
|
||||
|
||||
/**
|
||||
* Main constructor
|
||||
*
|
||||
* @param codewords the codewords to place
|
||||
* @param numcols the number of columns
|
||||
* @param numrows the number of rows
|
||||
*/
|
||||
pub fn new( codewords: &CharSequence, numcols: i32, numrows: i32) -> DefaultPlacement {
|
||||
let .codewords = codewords;
|
||||
let .numcols = numcols;
|
||||
let .numrows = numrows;
|
||||
let .bits = : [i8; numcols * numrows] = [0; numcols * numrows];
|
||||
//Initialize with "not set" value
|
||||
Arrays::fill(let .bits, -1 as i8);
|
||||
}
|
||||
|
||||
fn get_numrows(&self) -> i32 {
|
||||
return self.numrows;
|
||||
}
|
||||
|
||||
fn get_numcols(&self) -> i32 {
|
||||
return self.numcols;
|
||||
}
|
||||
|
||||
fn get_bits(&self) -> Vec<i8> {
|
||||
return self.bits;
|
||||
}
|
||||
|
||||
pub fn get_bit(&self, col: i32, row: i32) -> bool {
|
||||
return self.bits[row * self.numcols + col] == 1;
|
||||
}
|
||||
|
||||
fn set_bit(&self, col: i32, row: i32, bit: bool) {
|
||||
self.bits[row * self.numcols + col] = ( if bit { 1 } else { 0 }) as i8;
|
||||
}
|
||||
|
||||
fn no_bit(&self, col: i32, row: i32) -> bool {
|
||||
return self.bits[row * self.numcols + col] < 0;
|
||||
}
|
||||
|
||||
pub fn place(&self) {
|
||||
let mut pos: i32 = 0;
|
||||
let mut row: i32 = 4;
|
||||
let mut col: i32 = 0;
|
||||
loop { {
|
||||
// repeatedly first check for one of the special corner cases, then...
|
||||
if (row == self.numrows) && (col == 0) {
|
||||
self.corner1(pos += 1 !!!check!!! post increment);
|
||||
}
|
||||
if (row == self.numrows - 2) && (col == 0) && ((self.numcols % 4) != 0) {
|
||||
self.corner2(pos += 1 !!!check!!! post increment);
|
||||
}
|
||||
if (row == self.numrows - 2) && (col == 0) && (self.numcols % 8 == 4) {
|
||||
self.corner3(pos += 1 !!!check!!! post increment);
|
||||
}
|
||||
if (row == self.numrows + 4) && (col == 2) && ((self.numcols % 8) == 0) {
|
||||
self.corner4(pos += 1 !!!check!!! post increment);
|
||||
}
|
||||
// sweep upward diagonally, inserting successive characters...
|
||||
loop { {
|
||||
if (row < self.numrows) && (col >= 0) && self.no_bit(col, row) {
|
||||
self.utah(row, col, pos += 1 !!!check!!! post increment);
|
||||
}
|
||||
row -= 2;
|
||||
col += 2;
|
||||
}if !(row >= 0 && (col < self.numcols)) break;}
|
||||
row += 1;
|
||||
col += 3;
|
||||
// and then sweep downward diagonally, inserting successive characters, ...
|
||||
loop { {
|
||||
if (row >= 0) && (col < self.numcols) && self.no_bit(col, row) {
|
||||
self.utah(row, col, pos += 1 !!!check!!! post increment);
|
||||
}
|
||||
row += 2;
|
||||
col -= 2;
|
||||
}if !((row < self.numrows) && (col >= 0)) break;}
|
||||
row += 3;
|
||||
col += 1;
|
||||
// ...until the entire array is scanned
|
||||
}if !((row < self.numrows) || (col < self.numcols)) break;}
|
||||
// Lastly, if the lower right-hand corner is untouched, fill in fixed pattern
|
||||
if self.no_bit(self.numcols - 1, self.numrows - 1) {
|
||||
self.set_bit(self.numcols - 1, self.numrows - 1, true);
|
||||
self.set_bit(self.numcols - 2, self.numrows - 2, true);
|
||||
}
|
||||
}
|
||||
|
||||
fn module(&self, row: i32, col: i32, pos: i32, bit: i32) {
|
||||
if row < 0 {
|
||||
row += self.numrows;
|
||||
col += 4 - ((self.numrows + 4) % 8);
|
||||
}
|
||||
if col < 0 {
|
||||
col += self.numcols;
|
||||
row += 4 - ((self.numcols + 4) % 8);
|
||||
}
|
||||
// Note the conversion:
|
||||
let mut v: i32 = self.codewords.char_at(pos);
|
||||
v &= 1 << (8 - bit);
|
||||
self.set_bit(col, row, v != 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Places the 8 bits of a utah-shaped symbol character in ECC200.
|
||||
*
|
||||
* @param row the row
|
||||
* @param col the column
|
||||
* @param pos character position
|
||||
*/
|
||||
fn utah(&self, row: i32, col: i32, pos: i32) {
|
||||
self.module(row - 2, col - 2, pos, 1);
|
||||
self.module(row - 2, col - 1, pos, 2);
|
||||
self.module(row - 1, col - 2, pos, 3);
|
||||
self.module(row - 1, col - 1, pos, 4);
|
||||
self.module(row - 1, col, pos, 5);
|
||||
self.module(row, col - 2, pos, 6);
|
||||
self.module(row, col - 1, pos, 7);
|
||||
self.module(row, col, pos, 8);
|
||||
}
|
||||
|
||||
fn corner1(&self, pos: i32) {
|
||||
self.module(self.numrows - 1, 0, pos, 1);
|
||||
self.module(self.numrows - 1, 1, pos, 2);
|
||||
self.module(self.numrows - 1, 2, pos, 3);
|
||||
self.module(0, self.numcols - 2, pos, 4);
|
||||
self.module(0, self.numcols - 1, pos, 5);
|
||||
self.module(1, self.numcols - 1, pos, 6);
|
||||
self.module(2, self.numcols - 1, pos, 7);
|
||||
self.module(3, self.numcols - 1, pos, 8);
|
||||
}
|
||||
|
||||
fn corner2(&self, pos: i32) {
|
||||
self.module(self.numrows - 3, 0, pos, 1);
|
||||
self.module(self.numrows - 2, 0, pos, 2);
|
||||
self.module(self.numrows - 1, 0, pos, 3);
|
||||
self.module(0, self.numcols - 4, pos, 4);
|
||||
self.module(0, self.numcols - 3, pos, 5);
|
||||
self.module(0, self.numcols - 2, pos, 6);
|
||||
self.module(0, self.numcols - 1, pos, 7);
|
||||
self.module(1, self.numcols - 1, pos, 8);
|
||||
}
|
||||
|
||||
fn corner3(&self, pos: i32) {
|
||||
self.module(self.numrows - 3, 0, pos, 1);
|
||||
self.module(self.numrows - 2, 0, pos, 2);
|
||||
self.module(self.numrows - 1, 0, pos, 3);
|
||||
self.module(0, self.numcols - 2, pos, 4);
|
||||
self.module(0, self.numcols - 1, pos, 5);
|
||||
self.module(1, self.numcols - 1, pos, 6);
|
||||
self.module(2, self.numcols - 1, pos, 7);
|
||||
self.module(3, self.numcols - 1, pos, 8);
|
||||
}
|
||||
|
||||
fn corner4(&self, pos: i32) {
|
||||
self.module(self.numrows - 1, 0, pos, 1);
|
||||
self.module(self.numrows - 1, self.numcols - 1, pos, 2);
|
||||
self.module(0, self.numcols - 3, pos, 3);
|
||||
self.module(0, self.numcols - 2, pos, 4);
|
||||
self.module(0, self.numcols - 1, pos, 5);
|
||||
self.module(1, self.numcols - 3, pos, 6);
|
||||
self.module(1, self.numcols - 2, pos, 7);
|
||||
self.module(1, self.numcols - 1, pos, 8);
|
||||
}
|
||||
}
|
||||
|
||||
149
port_src/output/zxing/datamatrix/encoder/edifact_encoder.rs
Normal file
149
port_src/output/zxing/datamatrix/encoder/edifact_encoder.rs
Normal file
@@ -0,0 +1,149 @@
|
||||
/*
|
||||
* Copyright 2006-2007 Jeremias Maerki.
|
||||
*
|
||||
* 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::datamatrix::encoder;
|
||||
|
||||
#[derive(Encoder)]
|
||||
struct EdifactEncoder {
|
||||
}
|
||||
|
||||
impl EdifactEncoder {
|
||||
|
||||
pub fn get_encoding_mode(&self) -> i32 {
|
||||
return HighLevelEncoder::EDIFACT_ENCODATION;
|
||||
}
|
||||
|
||||
pub fn encode(&self, context: &EncoderContext) {
|
||||
//step F
|
||||
let buffer: StringBuilder = StringBuilder::new();
|
||||
while context.has_more_characters() {
|
||||
let c: char = context.get_current_char();
|
||||
::encode_char(c, &buffer);
|
||||
context.pos += 1;
|
||||
let count: i32 = buffer.length();
|
||||
if count >= 4 {
|
||||
context.write_codewords(&::encode_to_codewords(&buffer));
|
||||
buffer.delete(0, 4);
|
||||
let new_mode: i32 = HighLevelEncoder::look_ahead_test(&context.get_message(), context.pos, &self.get_encoding_mode());
|
||||
if new_mode != self.get_encoding_mode() {
|
||||
// Return to ASCII encodation, which will actually handle latch to new mode
|
||||
context.signal_encoder_change(HighLevelEncoder::ASCII_ENCODATION);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
//Unlatch
|
||||
buffer.append(31 as char);
|
||||
::handle_e_o_d(context, &buffer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle "end of data" situations
|
||||
*
|
||||
* @param context the encoder context
|
||||
* @param buffer the buffer with the remaining encoded characters
|
||||
*/
|
||||
fn handle_e_o_d( context: &EncoderContext, buffer: &CharSequence) {
|
||||
let tryResult1 = 0;
|
||||
'try1: loop {
|
||||
{
|
||||
let count: i32 = buffer.length();
|
||||
if count == 0 {
|
||||
//Already finished
|
||||
return;
|
||||
}
|
||||
if count == 1 {
|
||||
//Only an unlatch at the end
|
||||
context.update_symbol_info();
|
||||
let mut available: i32 = context.get_symbol_info().get_data_capacity() - context.get_codeword_count();
|
||||
let remaining: i32 = context.get_remaining_characters();
|
||||
// The following two lines are a hack inspired by the 'fix' from https://sourceforge.net/p/barcode4j/svn/221/
|
||||
if remaining > available {
|
||||
context.update_symbol_info(context.get_codeword_count() + 1);
|
||||
available = context.get_symbol_info().get_data_capacity() - context.get_codeword_count();
|
||||
}
|
||||
if remaining <= available && available <= 2 {
|
||||
//No unlatch
|
||||
return;
|
||||
}
|
||||
}
|
||||
if count > 4 {
|
||||
throw IllegalStateException::new("Count must not exceed 4");
|
||||
}
|
||||
let rest_chars: i32 = count - 1;
|
||||
let encoded: String = ::encode_to_codewords(&buffer);
|
||||
let end_of_symbol_reached: bool = !context.has_more_characters();
|
||||
let rest_in_ascii: bool = end_of_symbol_reached && rest_chars <= 2;
|
||||
if rest_chars <= 2 {
|
||||
context.update_symbol_info(context.get_codeword_count() + rest_chars);
|
||||
let available: i32 = context.get_symbol_info().get_data_capacity() - context.get_codeword_count();
|
||||
if available >= 3 {
|
||||
rest_in_ascii = false;
|
||||
context.update_symbol_info(context.get_codeword_count() + encoded.length());
|
||||
//available = context.symbolInfo.dataCapacity - context.getCodewordCount();
|
||||
}
|
||||
}
|
||||
if rest_in_ascii {
|
||||
context.reset_symbol_info();
|
||||
context.pos -= rest_chars;
|
||||
} else {
|
||||
context.write_codewords(&encoded);
|
||||
}
|
||||
}
|
||||
break 'try1
|
||||
}
|
||||
match tryResult1 {
|
||||
0 => break
|
||||
}
|
||||
finally {
|
||||
context.signal_encoder_change(HighLevelEncoder::ASCII_ENCODATION);
|
||||
}
|
||||
}
|
||||
|
||||
fn encode_char( c: char, sb: &StringBuilder) {
|
||||
if c >= ' ' && c <= '?' {
|
||||
sb.append(c);
|
||||
} else if c >= '@' && c <= '^' {
|
||||
sb.append((c - 64) as char);
|
||||
} else {
|
||||
HighLevelEncoder::illegal_character(c);
|
||||
}
|
||||
}
|
||||
|
||||
fn encode_to_codewords( sb: &CharSequence) -> String {
|
||||
let len: i32 = sb.length();
|
||||
if len == 0 {
|
||||
throw IllegalStateException::new("StringBuilder must not be empty");
|
||||
}
|
||||
let c1: char = sb.char_at(0);
|
||||
let c2: char = if len >= 2 { sb.char_at(1) } else { 0 };
|
||||
let c3: char = if len >= 3 { sb.char_at(2) } else { 0 };
|
||||
let c4: char = if len >= 4 { sb.char_at(3) } else { 0 };
|
||||
let v: i32 = (c1 << 18) + (c2 << 12) + (c3 << 6) + c4;
|
||||
let cw1: char = ((v >> 16) & 255) as char;
|
||||
let cw2: char = ((v >> 8) & 255) as char;
|
||||
let cw3: char = (v & 255) as char;
|
||||
let res: StringBuilder = StringBuilder::new(3);
|
||||
res.append(cw1);
|
||||
if len >= 2 {
|
||||
res.append(cw2);
|
||||
}
|
||||
if len >= 3 {
|
||||
res.append(cw3);
|
||||
}
|
||||
return res.to_string();
|
||||
}
|
||||
}
|
||||
|
||||
24
port_src/output/zxing/datamatrix/encoder/encoder.rs
Normal file
24
port_src/output/zxing/datamatrix/encoder/encoder.rs
Normal file
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright 2006-2007 Jeremias Maerki.
|
||||
*
|
||||
* 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::datamatrix::encoder;
|
||||
|
||||
trait Encoder {
|
||||
|
||||
fn get_encoding_mode(&self) -> i32 ;
|
||||
|
||||
fn encode(&self, context: &EncoderContext) ;
|
||||
}
|
||||
|
||||
149
port_src/output/zxing/datamatrix/encoder/encoder_context.rs
Normal file
149
port_src/output/zxing/datamatrix/encoder/encoder_context.rs
Normal file
@@ -0,0 +1,149 @@
|
||||
/*
|
||||
* Copyright 2006-2007 Jeremias Maerki.
|
||||
*
|
||||
* 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::datamatrix::encoder;
|
||||
|
||||
struct EncoderContext {
|
||||
|
||||
let msg: String;
|
||||
|
||||
let mut shape: SymbolShapeHint;
|
||||
|
||||
let min_size: Dimension;
|
||||
|
||||
let max_size: Dimension;
|
||||
|
||||
let mut codewords: StringBuilder;
|
||||
|
||||
let pos: i32;
|
||||
|
||||
let new_encoding: i32;
|
||||
|
||||
let symbol_info: SymbolInfo;
|
||||
|
||||
let skip_at_end: i32;
|
||||
}
|
||||
|
||||
impl EncoderContext {
|
||||
|
||||
fn new( msg: &String) -> EncoderContext {
|
||||
//From this point on Strings are not Unicode anymore!
|
||||
let msg_binary: Vec<i8> = msg.get_bytes(StandardCharsets::ISO_8859_1);
|
||||
let sb: StringBuilder = StringBuilder::new(msg_binary.len());
|
||||
{
|
||||
let mut i: i32 = 0, let c: i32 = msg_binary.len();
|
||||
while i < c {
|
||||
{
|
||||
let ch: char = (msg_binary[i] & 0xff) as char;
|
||||
if ch == '?' && msg.char_at(i) != '?' {
|
||||
throw IllegalArgumentException::new("Message contains characters outside ISO-8859-1 encoding.");
|
||||
}
|
||||
sb.append(ch);
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
//Not Unicode here!
|
||||
let .msg = sb.to_string();
|
||||
shape = SymbolShapeHint::FORCE_NONE;
|
||||
let .codewords = StringBuilder::new(&msg.length());
|
||||
new_encoding = -1;
|
||||
}
|
||||
|
||||
pub fn set_symbol_shape(&self, shape: &SymbolShapeHint) {
|
||||
self.shape = shape;
|
||||
}
|
||||
|
||||
pub fn set_size_constraints(&self, min_size: &Dimension, max_size: &Dimension) {
|
||||
self.minSize = min_size;
|
||||
self.maxSize = max_size;
|
||||
}
|
||||
|
||||
pub fn get_message(&self) -> String {
|
||||
return self.msg;
|
||||
}
|
||||
|
||||
pub fn set_skip_at_end(&self, count: i32) {
|
||||
self.skipAtEnd = count;
|
||||
}
|
||||
|
||||
pub fn get_current_char(&self) -> char {
|
||||
return self.msg.char_at(self.pos);
|
||||
}
|
||||
|
||||
pub fn get_current(&self) -> char {
|
||||
return self.msg.char_at(self.pos);
|
||||
}
|
||||
|
||||
pub fn get_codewords(&self) -> StringBuilder {
|
||||
return self.codewords;
|
||||
}
|
||||
|
||||
pub fn write_codewords(&self, codewords: &String) {
|
||||
self.codewords.append(&codewords);
|
||||
}
|
||||
|
||||
pub fn write_codeword(&self, codeword: char) {
|
||||
self.codewords.append(codeword);
|
||||
}
|
||||
|
||||
pub fn get_codeword_count(&self) -> i32 {
|
||||
return self.codewords.length();
|
||||
}
|
||||
|
||||
pub fn get_new_encoding(&self) -> i32 {
|
||||
return self.new_encoding;
|
||||
}
|
||||
|
||||
pub fn signal_encoder_change(&self, encoding: i32) {
|
||||
self.newEncoding = encoding;
|
||||
}
|
||||
|
||||
pub fn reset_encoder_signal(&self) {
|
||||
self.newEncoding = -1;
|
||||
}
|
||||
|
||||
pub fn has_more_characters(&self) -> bool {
|
||||
return self.pos < self.get_total_message_char_count();
|
||||
}
|
||||
|
||||
fn get_total_message_char_count(&self) -> i32 {
|
||||
return self.msg.length() - self.skip_at_end;
|
||||
}
|
||||
|
||||
pub fn get_remaining_characters(&self) -> i32 {
|
||||
return self.get_total_message_char_count() - self.pos;
|
||||
}
|
||||
|
||||
pub fn get_symbol_info(&self) -> SymbolInfo {
|
||||
return self.symbol_info;
|
||||
}
|
||||
|
||||
pub fn update_symbol_info(&self) {
|
||||
self.update_symbol_info(&self.get_codeword_count());
|
||||
}
|
||||
|
||||
pub fn update_symbol_info(&self, len: i32) {
|
||||
if self.symbolInfo == null || len > self.symbolInfo.get_data_capacity() {
|
||||
self.symbolInfo = SymbolInfo::lookup(len, self.shape, self.min_size, self.max_size, true);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn reset_symbol_info(&self) {
|
||||
self.symbolInfo = null;
|
||||
}
|
||||
}
|
||||
|
||||
227
port_src/output/zxing/datamatrix/encoder/error_correction.rs
Normal file
227
port_src/output/zxing/datamatrix/encoder/error_correction.rs
Normal file
@@ -0,0 +1,227 @@
|
||||
/*
|
||||
* Copyright 2006 Jeremias Maerki.
|
||||
*
|
||||
* 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::datamatrix::encoder;
|
||||
|
||||
/**
|
||||
* Error Correction Code for ECC200.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Lookup table which factors to use for which number of error correction codewords.
|
||||
* See FACTORS.
|
||||
*/
|
||||
const FACTOR_SETS: vec![Vec<i32>; 16] = vec![5, 7, 10, 11, 12, 14, 18, 20, 24, 28, 36, 42, 48, 56, 62, 68, ]
|
||||
;
|
||||
|
||||
/**
|
||||
* Precomputed polynomial factors for ECC 200.
|
||||
*/
|
||||
const FACTORS: vec![vec![Vec<Vec<i32>>; 68]; 16] = vec![vec![228, 48, 15, 111, 62, ]
|
||||
, vec![23, 68, 144, 134, 240, 92, 254, ]
|
||||
, vec![28, 24, 185, 166, 223, 248, 116, 255, 110, 61, ]
|
||||
, vec![175, 138, 205, 12, 194, 168, 39, 245, 60, 97, 120, ]
|
||||
, vec![41, 153, 158, 91, 61, 42, 142, 213, 97, 178, 100, 242, ]
|
||||
, vec![156, 97, 192, 252, 95, 9, 157, 119, 138, 45, 18, 186, 83, 185, ]
|
||||
, vec![83, 195, 100, 39, 188, 75, 66, 61, 241, 213, 109, 129, 94, 254, 225, 48, 90, 188, ]
|
||||
, vec![15, 195, 244, 9, 233, 71, 168, 2, 188, 160, 153, 145, 253, 79, 108, 82, 27, 174, 186, 172, ]
|
||||
, vec![52, 190, 88, 205, 109, 39, 176, 21, 155, 197, 251, 223, 155, 21, 5, 172, 254, 124, 12, 181, 184, 96, 50, 193, ]
|
||||
, vec![211, 231, 43, 97, 71, 96, 103, 174, 37, 151, 170, 53, 75, 34, 249, 121, 17, 138, 110, 213, 141, 136, 120, 151, 233, 168, 93, 255, ]
|
||||
, vec![245, 127, 242, 218, 130, 250, 162, 181, 102, 120, 84, 179, 220, 251, 80, 182, 229, 18, 2, 4, 68, 33, 101, 137, 95, 119, 115, 44, 175, 184, 59, 25, 225, 98, 81, 112, ]
|
||||
, vec![77, 193, 137, 31, 19, 38, 22, 153, 247, 105, 122, 2, 245, 133, 242, 8, 175, 95, 100, 9, 167, 105, 214, 111, 57, 121, 21, 1, 253, 57, 54, 101, 248, 202, 69, 50, 150, 177, 226, 5, 9, 5, ]
|
||||
, vec![245, 132, 172, 223, 96, 32, 117, 22, 238, 133, 238, 231, 205, 188, 237, 87, 191, 106, 16, 147, 118, 23, 37, 90, 170, 205, 131, 88, 120, 100, 66, 138, 186, 240, 82, 44, 176, 87, 187, 147, 160, 175, 69, 213, 92, 253, 225, 19, ]
|
||||
, vec![175, 9, 223, 238, 12, 17, 220, 208, 100, 29, 175, 170, 230, 192, 215, 235, 150, 159, 36, 223, 38, 200, 132, 54, 228, 146, 218, 234, 117, 203, 29, 232, 144, 238, 22, 150, 201, 117, 62, 207, 164, 13, 137, 245, 127, 67, 247, 28, 155, 43, 203, 107, 233, 53, 143, 46, ]
|
||||
, vec![242, 93, 169, 50, 144, 210, 39, 118, 202, 188, 201, 189, 143, 108, 196, 37, 185, 112, 134, 230, 245, 63, 197, 190, 250, 106, 185, 221, 175, 64, 114, 71, 161, 44, 147, 6, 27, 218, 51, 63, 87, 10, 40, 130, 188, 17, 163, 31, 176, 170, 4, 107, 232, 7, 94, 166, 224, 124, 86, 47, 11, 204, ]
|
||||
, vec![220, 228, 173, 89, 251, 149, 159, 56, 89, 33, 147, 244, 154, 36, 73, 127, 213, 136, 248, 180, 234, 197, 158, 177, 68, 122, 93, 213, 15, 160, 227, 236, 66, 139, 153, 185, 202, 167, 179, 25, 220, 232, 96, 210, 231, 136, 223, 239, 181, 241, 59, 52, 172, 25, 49, 232, 211, 189, 64, 54, 108, 153, 132, 63, 96, 103, 82, 186, ]
|
||||
, ]
|
||||
;
|
||||
|
||||
const MODULO_VALUE: i32 = 0x12D;
|
||||
|
||||
const LOG: Vec<i32>;
|
||||
|
||||
const ALOG: Vec<i32>;
|
||||
pub struct ErrorCorrection {
|
||||
}
|
||||
|
||||
impl ErrorCorrection {
|
||||
|
||||
static {
|
||||
//Create log and antilog table
|
||||
LOG = : [i32; 256] = [0; 256];
|
||||
ALOG = : [i32; 255] = [0; 255];
|
||||
let mut p: i32 = 1;
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < 255 {
|
||||
{
|
||||
ALOG[i] = p;
|
||||
LOG[p] = i;
|
||||
p *= 2;
|
||||
if p >= 256 {
|
||||
p ^= MODULO_VALUE;
|
||||
}
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fn new() -> ErrorCorrection {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the ECC200 error correction for an encoded message.
|
||||
*
|
||||
* @param codewords the codewords
|
||||
* @param symbolInfo information about the symbol to be encoded
|
||||
* @return the codewords with interleaved error correction.
|
||||
*/
|
||||
pub fn encode_e_c_c200( codewords: &String, symbol_info: &SymbolInfo) -> String {
|
||||
if codewords.length() != symbol_info.get_data_capacity() {
|
||||
throw IllegalArgumentException::new("The number of codewords does not match the selected symbol");
|
||||
}
|
||||
let sb: StringBuilder = StringBuilder::new(symbol_info.get_data_capacity() + symbol_info.get_error_codewords());
|
||||
sb.append(&codewords);
|
||||
let block_count: i32 = symbol_info.get_interleaved_block_count();
|
||||
if block_count == 1 {
|
||||
let ecc: String = ::create_e_c_c_block(&codewords, &symbol_info.get_error_codewords());
|
||||
sb.append(&ecc);
|
||||
} else {
|
||||
sb.set_length(&sb.capacity());
|
||||
let data_sizes: [i32; block_count] = [0; block_count];
|
||||
let error_sizes: [i32; block_count] = [0; block_count];
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < block_count {
|
||||
{
|
||||
data_sizes[i] = symbol_info.get_data_length_for_interleaved_block(i + 1);
|
||||
error_sizes[i] = symbol_info.get_error_length_for_interleaved_block(i + 1);
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
let mut block: i32 = 0;
|
||||
while block < block_count {
|
||||
{
|
||||
let temp: StringBuilder = StringBuilder::new(data_sizes[block]);
|
||||
{
|
||||
let mut d: i32 = block;
|
||||
while d < symbol_info.get_data_capacity() {
|
||||
{
|
||||
temp.append(&codewords.char_at(d));
|
||||
}
|
||||
d += block_count;
|
||||
}
|
||||
}
|
||||
|
||||
let ecc: String = ::create_e_c_c_block(&temp.to_string(), error_sizes[block]);
|
||||
let mut pos: i32 = 0;
|
||||
{
|
||||
let mut e: i32 = block;
|
||||
while e < error_sizes[block] * block_count {
|
||||
{
|
||||
sb.set_char_at(symbol_info.get_data_capacity() + e, &ecc.char_at(pos += 1 !!!check!!! post increment));
|
||||
}
|
||||
e += block_count;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
block += 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return sb.to_string();
|
||||
}
|
||||
|
||||
fn create_e_c_c_block( codewords: &CharSequence, num_e_c_words: i32) -> String {
|
||||
let mut table: i32 = -1;
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < FACTOR_SETS.len() {
|
||||
{
|
||||
if FACTOR_SETS[i] == num_e_c_words {
|
||||
table = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
if table < 0 {
|
||||
throw IllegalArgumentException::new(format!("Illegal number of error correction codewords specified: {}", num_e_c_words));
|
||||
}
|
||||
let poly: Vec<i32> = FACTORS[table];
|
||||
let mut ecc: [Option<char>; num_e_c_words] = [None; num_e_c_words];
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < num_e_c_words {
|
||||
{
|
||||
ecc[i] = 0;
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < codewords.length() {
|
||||
{
|
||||
let m: i32 = ecc[num_e_c_words - 1] ^ codewords.char_at(i);
|
||||
{
|
||||
let mut k: i32 = num_e_c_words - 1;
|
||||
while k > 0 {
|
||||
{
|
||||
if m != 0 && poly[k] != 0 {
|
||||
ecc[k] = (ecc[k - 1] ^ ALOG[(LOG[m] + LOG[poly[k]]) % 255]) as char;
|
||||
} else {
|
||||
ecc[k] = ecc[k - 1];
|
||||
}
|
||||
}
|
||||
k -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
if m != 0 && poly[0] != 0 {
|
||||
ecc[0] = ALOG[(LOG[m] + LOG[poly[0]]) % 255] as char;
|
||||
} else {
|
||||
ecc[0] = 0;
|
||||
}
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
let ecc_reversed: [Option<char>; num_e_c_words] = [None; num_e_c_words];
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < num_e_c_words {
|
||||
{
|
||||
ecc_reversed[i] = ecc[num_e_c_words - i - 1];
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
return String::value_of(&ecc_reversed);
|
||||
}
|
||||
}
|
||||
|
||||
491
port_src/output/zxing/datamatrix/encoder/high_level_encoder.rs
Normal file
491
port_src/output/zxing/datamatrix/encoder/high_level_encoder.rs
Normal file
@@ -0,0 +1,491 @@
|
||||
/*
|
||||
* Copyright 2006-2007 Jeremias Maerki.
|
||||
*
|
||||
* 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::datamatrix::encoder;
|
||||
|
||||
/**
|
||||
* DataMatrix ECC 200 data encoder following the algorithm described in ISO/IEC 16022:200(E) in
|
||||
* annex S.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Padding character
|
||||
*/
|
||||
const PAD: char = 129;
|
||||
|
||||
/**
|
||||
* mode latch to C40 encodation mode
|
||||
*/
|
||||
const LATCH_TO_C40: char = 230;
|
||||
|
||||
/**
|
||||
* mode latch to Base 256 encodation mode
|
||||
*/
|
||||
const LATCH_TO_BASE256: char = 231;
|
||||
|
||||
/**
|
||||
* FNC1 Codeword
|
||||
*/
|
||||
//private static final char FNC1 = 232;
|
||||
/**
|
||||
* Structured Append Codeword
|
||||
*/
|
||||
//private static final char STRUCTURED_APPEND = 233;
|
||||
/**
|
||||
* Reader Programming
|
||||
*/
|
||||
//private static final char READER_PROGRAMMING = 234;
|
||||
/**
|
||||
* Upper Shift
|
||||
*/
|
||||
const UPPER_SHIFT: char = 235;
|
||||
|
||||
/**
|
||||
* 05 Macro
|
||||
*/
|
||||
const MACRO_05: char = 236;
|
||||
|
||||
/**
|
||||
* 06 Macro
|
||||
*/
|
||||
const MACRO_06: char = 237;
|
||||
|
||||
/**
|
||||
* mode latch to ANSI X.12 encodation mode
|
||||
*/
|
||||
const LATCH_TO_ANSIX12: char = 238;
|
||||
|
||||
/**
|
||||
* mode latch to Text encodation mode
|
||||
*/
|
||||
const LATCH_TO_TEXT: char = 239;
|
||||
|
||||
/**
|
||||
* mode latch to EDIFACT encodation mode
|
||||
*/
|
||||
const LATCH_TO_EDIFACT: char = 240;
|
||||
|
||||
/**
|
||||
* ECI character (Extended Channel Interpretation)
|
||||
*/
|
||||
//private static final char ECI = 241;
|
||||
/**
|
||||
* Unlatch from C40 encodation
|
||||
*/
|
||||
const C40_UNLATCH: char = 254;
|
||||
|
||||
/**
|
||||
* Unlatch from X12 encodation
|
||||
*/
|
||||
const X12_UNLATCH: char = 254;
|
||||
|
||||
/**
|
||||
* 05 Macro header
|
||||
*/
|
||||
const MACRO_05_HEADER: &'static str = "[)>05";
|
||||
|
||||
/**
|
||||
* 06 Macro header
|
||||
*/
|
||||
const MACRO_06_HEADER: &'static str = "[)>06";
|
||||
|
||||
/**
|
||||
* Macro trailer
|
||||
*/
|
||||
const MACRO_TRAILER: &'static str = "";
|
||||
|
||||
const ASCII_ENCODATION: i32 = 0;
|
||||
|
||||
const C40_ENCODATION: i32 = 1;
|
||||
|
||||
const TEXT_ENCODATION: i32 = 2;
|
||||
|
||||
const X12_ENCODATION: i32 = 3;
|
||||
|
||||
const EDIFACT_ENCODATION: i32 = 4;
|
||||
|
||||
const BASE256_ENCODATION: i32 = 5;
|
||||
pub struct HighLevelEncoder {
|
||||
}
|
||||
|
||||
impl HighLevelEncoder {
|
||||
|
||||
fn new() -> HighLevelEncoder {
|
||||
}
|
||||
|
||||
fn randomize253_state( codeword_position: i32) -> char {
|
||||
let pseudo_random: i32 = ((149 * codeword_position) % 253) + 1;
|
||||
let temp_variable: i32 = PAD + pseudo_random;
|
||||
return ( if temp_variable <= 254 { temp_variable } else { temp_variable - 254 }) as char;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs message encoding of a DataMatrix message using the algorithm described in annex P
|
||||
* of ISO/IEC 16022:2000(E).
|
||||
*
|
||||
* @param msg the message
|
||||
* @return the encoded message (the char values range from 0 to 255)
|
||||
*/
|
||||
pub fn encode_high_level( msg: &String) -> String {
|
||||
return ::encode_high_level(&msg, SymbolShapeHint::FORCE_NONE, null, null, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs message encoding of a DataMatrix message using the algorithm described in annex P
|
||||
* of ISO/IEC 16022:2000(E).
|
||||
*
|
||||
* @param msg the message
|
||||
* @param shape requested shape. May be {@code SymbolShapeHint.FORCE_NONE},
|
||||
* {@code SymbolShapeHint.FORCE_SQUARE} or {@code SymbolShapeHint.FORCE_RECTANGLE}.
|
||||
* @param minSize the minimum symbol size constraint or null for no constraint
|
||||
* @param maxSize the maximum symbol size constraint or null for no constraint
|
||||
* @return the encoded message (the char values range from 0 to 255)
|
||||
*/
|
||||
pub fn encode_high_level( msg: &String, shape: &SymbolShapeHint, min_size: &Dimension, max_size: &Dimension) -> String {
|
||||
return ::encode_high_level(&msg, shape, min_size, max_size, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs message encoding of a DataMatrix message using the algorithm described in annex P
|
||||
* of ISO/IEC 16022:2000(E).
|
||||
*
|
||||
* @param msg the message
|
||||
* @param shape requested shape. May be {@code SymbolShapeHint.FORCE_NONE},
|
||||
* {@code SymbolShapeHint.FORCE_SQUARE} or {@code SymbolShapeHint.FORCE_RECTANGLE}.
|
||||
* @param minSize the minimum symbol size constraint or null for no constraint
|
||||
* @param maxSize the maximum symbol size constraint or null for no constraint
|
||||
* @param forceC40 enforce C40 encoding
|
||||
* @return the encoded message (the char values range from 0 to 255)
|
||||
*/
|
||||
pub fn encode_high_level( msg: &String, shape: &SymbolShapeHint, min_size: &Dimension, max_size: &Dimension, force_c40: bool) -> String {
|
||||
//the codewords 0..255 are encoded as Unicode characters
|
||||
let c40_encoder: C40Encoder = C40Encoder::new();
|
||||
let encoders: vec![Vec<Encoder>; 6] = vec![ASCIIEncoder::new(), c40_encoder, TextEncoder::new(), X12Encoder::new(), EdifactEncoder::new(), Base256Encoder::new(), ]
|
||||
;
|
||||
let mut context: EncoderContext = EncoderContext::new(&msg);
|
||||
context.set_symbol_shape(shape);
|
||||
context.set_size_constraints(min_size, max_size);
|
||||
if msg.starts_with(&MACRO_05_HEADER) && msg.ends_with(&MACRO_TRAILER) {
|
||||
context.write_codeword(MACRO_05);
|
||||
context.set_skip_at_end(2);
|
||||
context.pos += MACRO_05_HEADER::length();
|
||||
} else if msg.starts_with(&MACRO_06_HEADER) && msg.ends_with(&MACRO_TRAILER) {
|
||||
context.write_codeword(MACRO_06);
|
||||
context.set_skip_at_end(2);
|
||||
context.pos += MACRO_06_HEADER::length();
|
||||
}
|
||||
//Default mode
|
||||
let encoding_mode: i32 = ASCII_ENCODATION;
|
||||
if force_c40 {
|
||||
c40_encoder.encode_maximal(context);
|
||||
encoding_mode = context.get_new_encoding();
|
||||
context.reset_encoder_signal();
|
||||
}
|
||||
while context.has_more_characters() {
|
||||
encoders[encoding_mode].encode(context);
|
||||
if context.get_new_encoding() >= 0 {
|
||||
encoding_mode = context.get_new_encoding();
|
||||
context.reset_encoder_signal();
|
||||
}
|
||||
}
|
||||
let len: i32 = context.get_codeword_count();
|
||||
context.update_symbol_info();
|
||||
let capacity: i32 = context.get_symbol_info().get_data_capacity();
|
||||
if len < capacity && encoding_mode != ASCII_ENCODATION && encoding_mode != BASE256_ENCODATION && encoding_mode != EDIFACT_ENCODATION {
|
||||
//Unlatch (254)
|
||||
context.write_codeword('þ');
|
||||
}
|
||||
//Padding
|
||||
let codewords: StringBuilder = context.get_codewords();
|
||||
if codewords.length() < capacity {
|
||||
codewords.append(PAD);
|
||||
}
|
||||
while codewords.length() < capacity {
|
||||
codewords.append(&::randomize253_state(codewords.length() + 1));
|
||||
}
|
||||
return context.get_codewords().to_string();
|
||||
}
|
||||
|
||||
fn look_ahead_test( msg: &CharSequence, startpos: i32, current_mode: i32) -> i32 {
|
||||
let new_mode: i32 = ::look_ahead_test_intern(&msg, startpos, current_mode);
|
||||
if current_mode == X12_ENCODATION && new_mode == X12_ENCODATION {
|
||||
let endpos: i32 = Math::min(startpos + 3, &msg.length());
|
||||
{
|
||||
let mut i: i32 = startpos;
|
||||
while i < endpos {
|
||||
{
|
||||
if !::is_native_x12(&msg.char_at(i)) {
|
||||
return ASCII_ENCODATION;
|
||||
}
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
} else if current_mode == EDIFACT_ENCODATION && new_mode == EDIFACT_ENCODATION {
|
||||
let endpos: i32 = Math::min(startpos + 4, &msg.length());
|
||||
{
|
||||
let mut i: i32 = startpos;
|
||||
while i < endpos {
|
||||
{
|
||||
if !::is_native_e_d_i_f_a_c_t(&msg.char_at(i)) {
|
||||
return ASCII_ENCODATION;
|
||||
}
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return new_mode;
|
||||
}
|
||||
|
||||
fn look_ahead_test_intern( msg: &CharSequence, startpos: i32, current_mode: i32) -> i32 {
|
||||
if startpos >= msg.length() {
|
||||
return current_mode;
|
||||
}
|
||||
let char_counts: Vec<f32>;
|
||||
//step J
|
||||
if current_mode == ASCII_ENCODATION {
|
||||
char_counts = : vec![f32; 6] = vec![0.0, 1.0, 1.0, 1.0, 1.0, 1.25f, ]
|
||||
;
|
||||
} else {
|
||||
char_counts = : vec![f32; 6] = vec![1.0, 2.0, 2.0, 2.0, 2.0, 2.25f, ]
|
||||
;
|
||||
char_counts[current_mode] = 0.0;
|
||||
}
|
||||
let chars_processed: i32 = 0;
|
||||
let mins: [i8; 6] = [0; 6];
|
||||
let int_char_counts: [i32; 6] = [0; 6];
|
||||
while true {
|
||||
//step K
|
||||
if (startpos + chars_processed) == msg.length() {
|
||||
Arrays::fill(&mins, 0 as i8);
|
||||
Arrays::fill(&int_char_counts, 0);
|
||||
let min: i32 = ::find_minimums(&char_counts, &int_char_counts, Integer::MAX_VALUE, &mins);
|
||||
let min_count: i32 = ::get_minimum_count(&mins);
|
||||
if int_char_counts[ASCII_ENCODATION] == min {
|
||||
return ASCII_ENCODATION;
|
||||
}
|
||||
if min_count == 1 {
|
||||
if mins[BASE256_ENCODATION] > 0 {
|
||||
return BASE256_ENCODATION;
|
||||
}
|
||||
if mins[EDIFACT_ENCODATION] > 0 {
|
||||
return EDIFACT_ENCODATION;
|
||||
}
|
||||
if mins[TEXT_ENCODATION] > 0 {
|
||||
return TEXT_ENCODATION;
|
||||
}
|
||||
if mins[X12_ENCODATION] > 0 {
|
||||
return X12_ENCODATION;
|
||||
}
|
||||
}
|
||||
return C40_ENCODATION;
|
||||
}
|
||||
let c: char = msg.char_at(startpos + chars_processed);
|
||||
chars_processed += 1;
|
||||
//step L
|
||||
if ::is_digit(c) {
|
||||
char_counts[ASCII_ENCODATION] += 0.5f;
|
||||
} else if ::is_extended_a_s_c_i_i(c) {
|
||||
char_counts[ASCII_ENCODATION] = Math::ceil(char_counts[ASCII_ENCODATION]) as f32;
|
||||
char_counts[ASCII_ENCODATION] += 2.0f;
|
||||
} else {
|
||||
char_counts[ASCII_ENCODATION] = Math::ceil(char_counts[ASCII_ENCODATION]) as f32;
|
||||
char_counts[ASCII_ENCODATION] += 1;
|
||||
}
|
||||
//step M
|
||||
if ::is_native_c40(c) {
|
||||
char_counts[C40_ENCODATION] += 2.0f / 3.0f;
|
||||
} else if ::is_extended_a_s_c_i_i(c) {
|
||||
char_counts[C40_ENCODATION] += 8.0f / 3.0f;
|
||||
} else {
|
||||
char_counts[C40_ENCODATION] += 4.0f / 3.0f;
|
||||
}
|
||||
//step N
|
||||
if ::is_native_text(c) {
|
||||
char_counts[TEXT_ENCODATION] += 2.0f / 3.0f;
|
||||
} else if ::is_extended_a_s_c_i_i(c) {
|
||||
char_counts[TEXT_ENCODATION] += 8.0f / 3.0f;
|
||||
} else {
|
||||
char_counts[TEXT_ENCODATION] += 4.0f / 3.0f;
|
||||
}
|
||||
//step O
|
||||
if ::is_native_x12(c) {
|
||||
char_counts[X12_ENCODATION] += 2.0f / 3.0f;
|
||||
} else if ::is_extended_a_s_c_i_i(c) {
|
||||
char_counts[X12_ENCODATION] += 13.0f / 3.0f;
|
||||
} else {
|
||||
char_counts[X12_ENCODATION] += 10.0f / 3.0f;
|
||||
}
|
||||
//step P
|
||||
if ::is_native_e_d_i_f_a_c_t(c) {
|
||||
char_counts[EDIFACT_ENCODATION] += 3.0f / 4.0f;
|
||||
} else if ::is_extended_a_s_c_i_i(c) {
|
||||
char_counts[EDIFACT_ENCODATION] += 17.0f / 4.0f;
|
||||
} else {
|
||||
char_counts[EDIFACT_ENCODATION] += 13.0f / 4.0f;
|
||||
}
|
||||
// step Q
|
||||
if ::is_special_b256(c) {
|
||||
char_counts[BASE256_ENCODATION] += 4.0f;
|
||||
} else {
|
||||
char_counts[BASE256_ENCODATION] += 1;
|
||||
}
|
||||
//step R
|
||||
if chars_processed >= 4 {
|
||||
Arrays::fill(&mins, 0 as i8);
|
||||
Arrays::fill(&int_char_counts, 0);
|
||||
::find_minimums(&char_counts, &int_char_counts, Integer::MAX_VALUE, &mins);
|
||||
if int_char_counts[ASCII_ENCODATION] < ::min(int_char_counts[BASE256_ENCODATION], int_char_counts[C40_ENCODATION], int_char_counts[TEXT_ENCODATION], int_char_counts[X12_ENCODATION], int_char_counts[EDIFACT_ENCODATION]) {
|
||||
return ASCII_ENCODATION;
|
||||
}
|
||||
if int_char_counts[BASE256_ENCODATION] < int_char_counts[ASCII_ENCODATION] || int_char_counts[BASE256_ENCODATION] + 1 < ::min(int_char_counts[C40_ENCODATION], int_char_counts[TEXT_ENCODATION], int_char_counts[X12_ENCODATION], int_char_counts[EDIFACT_ENCODATION]) {
|
||||
return BASE256_ENCODATION;
|
||||
}
|
||||
if int_char_counts[EDIFACT_ENCODATION] + 1 < ::min(int_char_counts[BASE256_ENCODATION], int_char_counts[C40_ENCODATION], int_char_counts[TEXT_ENCODATION], int_char_counts[X12_ENCODATION], int_char_counts[ASCII_ENCODATION]) {
|
||||
return EDIFACT_ENCODATION;
|
||||
}
|
||||
if int_char_counts[TEXT_ENCODATION] + 1 < ::min(int_char_counts[BASE256_ENCODATION], int_char_counts[C40_ENCODATION], int_char_counts[EDIFACT_ENCODATION], int_char_counts[X12_ENCODATION], int_char_counts[ASCII_ENCODATION]) {
|
||||
return TEXT_ENCODATION;
|
||||
}
|
||||
if int_char_counts[X12_ENCODATION] + 1 < ::min(int_char_counts[BASE256_ENCODATION], int_char_counts[C40_ENCODATION], int_char_counts[EDIFACT_ENCODATION], int_char_counts[TEXT_ENCODATION], int_char_counts[ASCII_ENCODATION]) {
|
||||
return X12_ENCODATION;
|
||||
}
|
||||
if int_char_counts[C40_ENCODATION] + 1 < ::min(int_char_counts[ASCII_ENCODATION], int_char_counts[BASE256_ENCODATION], int_char_counts[EDIFACT_ENCODATION], int_char_counts[TEXT_ENCODATION]) {
|
||||
if int_char_counts[C40_ENCODATION] < int_char_counts[X12_ENCODATION] {
|
||||
return C40_ENCODATION;
|
||||
}
|
||||
if int_char_counts[C40_ENCODATION] == int_char_counts[X12_ENCODATION] {
|
||||
let mut p: i32 = startpos + chars_processed + 1;
|
||||
while p < msg.length() {
|
||||
let tc: char = msg.char_at(p);
|
||||
if ::is_x12_term_sep(tc) {
|
||||
return X12_ENCODATION;
|
||||
}
|
||||
if !::is_native_x12(tc) {
|
||||
break;
|
||||
}
|
||||
p += 1;
|
||||
}
|
||||
return C40_ENCODATION;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn min( f1: i32, f2: i32, f3: i32, f4: i32, f5: i32) -> i32 {
|
||||
return Math::min(&::min(f1, f2, f3, f4), f5);
|
||||
}
|
||||
|
||||
fn min( f1: i32, f2: i32, f3: i32, f4: i32) -> i32 {
|
||||
return Math::min(f1, &Math::min(f2, &Math::min(f3, f4)));
|
||||
}
|
||||
|
||||
fn find_minimums( char_counts: &Vec<f32>, int_char_counts: &Vec<i32>, min: i32, mins: &Vec<i8>) -> i32 {
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < 6 {
|
||||
{
|
||||
let current: i32 = (int_char_counts[i] = Math::ceil(char_counts[i]) as i32);
|
||||
if min > current {
|
||||
min = current;
|
||||
Arrays::fill(&mins, 0 as i8);
|
||||
}
|
||||
if min == current {
|
||||
mins[i] += 1;
|
||||
}
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
return min;
|
||||
}
|
||||
|
||||
fn get_minimum_count( mins: &Vec<i8>) -> i32 {
|
||||
let min_count: i32 = 0;
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < 6 {
|
||||
{
|
||||
min_count += mins[i];
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
return min_count;
|
||||
}
|
||||
|
||||
fn is_digit( ch: char) -> bool {
|
||||
return ch >= '0' && ch <= '9';
|
||||
}
|
||||
|
||||
fn is_extended_a_s_c_i_i( ch: char) -> bool {
|
||||
return ch >= 128 && ch <= 255;
|
||||
}
|
||||
|
||||
fn is_native_c40( ch: char) -> bool {
|
||||
return (ch == ' ') || (ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'Z');
|
||||
}
|
||||
|
||||
fn is_native_text( ch: char) -> bool {
|
||||
return (ch == ' ') || (ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'z');
|
||||
}
|
||||
|
||||
fn is_native_x12( ch: char) -> bool {
|
||||
return ::is_x12_term_sep(ch) || (ch == ' ') || (ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'Z');
|
||||
}
|
||||
|
||||
fn is_x12_term_sep( ch: char) -> bool {
|
||||
return //CR
|
||||
(ch == '\r') || (ch == '*') || (ch == '>');
|
||||
}
|
||||
|
||||
fn is_native_e_d_i_f_a_c_t( ch: char) -> bool {
|
||||
return ch >= ' ' && ch <= '^';
|
||||
}
|
||||
|
||||
fn is_special_b256( ch: char) -> bool {
|
||||
//TODO NOT IMPLEMENTED YET!!!
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the number of consecutive characters that are encodable using numeric compaction.
|
||||
*
|
||||
* @param msg the message
|
||||
* @param startpos the start position within the message
|
||||
* @return the requested character count
|
||||
*/
|
||||
pub fn determine_consecutive_digit_count( msg: &CharSequence, startpos: i32) -> i32 {
|
||||
let len: i32 = msg.length();
|
||||
let mut idx: i32 = startpos;
|
||||
while idx < len && ::is_digit(&msg.char_at(idx)) {
|
||||
idx += 1;
|
||||
}
|
||||
return idx - startpos;
|
||||
}
|
||||
|
||||
fn illegal_character( c: char) {
|
||||
let mut hex: String = Integer::to_hex_string(c);
|
||||
hex = format!("{}{}", "0000".substring(0, 4 - hex.length()), hex);
|
||||
throw IllegalArgumentException::new(format!("Illegal character: {} (0x{})", c, hex));
|
||||
}
|
||||
}
|
||||
|
||||
947
port_src/output/zxing/datamatrix/encoder/minimal_encoder.rs
Normal file
947
port_src/output/zxing/datamatrix/encoder/minimal_encoder.rs
Normal file
@@ -0,0 +1,947 @@
|
||||
/*
|
||||
* Copyright 2021 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::datamatrix::encoder;
|
||||
|
||||
/**
|
||||
* Encoder that encodes minimally
|
||||
*
|
||||
* Algorithm:
|
||||
*
|
||||
* Uses Dijkstra to produce mathematically minimal encodings that are in some cases smaller than the results produced
|
||||
* by the algorithm described in annex S in the specification ISO/IEC 16022:200(E). The biggest improvment of this
|
||||
* algorithm over that one is the case when the algorithm enters the most inefficient mode, the B256 mode. The
|
||||
* algorithm from the specification algorithm will exit this mode only if it encounters digits so that arbitrarily
|
||||
* inefficient results can be produced if the postfix contains no digits.
|
||||
*
|
||||
* Multi ECI support and ECI switching:
|
||||
*
|
||||
* For multi language content the algorithm selects the most compact representation using ECI modes. Note that unlike
|
||||
* the compaction algorithm used for QR-Codes, this implementation operates in two stages and therfore is not
|
||||
* mathematically optimal. In the first stage, the input string is encoded minimally as a stream of ECI character set
|
||||
* selectors and bytes encoded in the selected encoding. In this stage the algorithm might for example decide to
|
||||
* encode ocurrences of the characters "\u0150\u015C" (O-double-acute, S-circumflex) in UTF-8 by a single ECI or
|
||||
* alternatively by multiple ECIs that switch between IS0-8859-2 and ISO-8859-3 (e.g. in the case that the input
|
||||
* contains many * characters from ISO-8859-2 (Latin 2) and few from ISO-8859-3 (Latin 3)).
|
||||
* In a second stage this stream of ECIs and bytes is minimally encoded using the various Data Matrix encoding modes.
|
||||
* While both stages encode mathematically minimally it is not ensured that the result is mathematically minimal since
|
||||
* the size growth for inserting an ECI in the first stage can only be approximated as the first stage does not know
|
||||
* in which mode the ECI will occur in the second stage (may, or may not require an extra latch to ASCII depending on
|
||||
* the current mode). The reason for this shortcoming are difficulties in implementing it in a straightforward and
|
||||
* readable manner.
|
||||
*
|
||||
* GS1 support
|
||||
*
|
||||
* FNC1 delimiters can be encoded in the input string by using the FNC1 character specified in the encoding function.
|
||||
* When a FNC1 character is specified then a leading FNC1 will be encoded and all ocurrences of delimiter characters
|
||||
* while result in FNC1 codewords in the symbol.
|
||||
*
|
||||
* @author Alex Geller
|
||||
*/
|
||||
|
||||
const C40_SHIFT2_CHARS: vec![Vec<char>; 27] = vec!['!', '"', '#', '$', '%', '&', '\'', '(', ')', '*', '+', ',', '-', '.', '/', ':', ';', '<', '=', '>', '?', '@', '[', '\\', ']', '^', '_', ]
|
||||
;
|
||||
pub struct MinimalEncoder {
|
||||
}
|
||||
|
||||
impl MinimalEncoder {
|
||||
|
||||
enum Mode {
|
||||
|
||||
ASCII(), C40(), TEXT(), X12(), EDF(), B256()
|
||||
}
|
||||
|
||||
fn new() -> MinimalEncoder {
|
||||
}
|
||||
|
||||
fn is_extended_a_s_c_i_i( ch: char, fnc1: i32) -> bool {
|
||||
return ch != fnc1 && ch >= 128 && ch <= 255;
|
||||
}
|
||||
|
||||
fn is_in_c40_shift1_set( ch: char) -> bool {
|
||||
return ch <= 31;
|
||||
}
|
||||
|
||||
fn is_in_c40_shift2_set( ch: char, fnc1: i32) -> bool {
|
||||
for let c40_shift2_char: char in C40_SHIFT2_CHARS {
|
||||
if c40_shift2_char == ch {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return ch == fnc1;
|
||||
}
|
||||
|
||||
fn is_in_text_shift1_set( ch: char) -> bool {
|
||||
return ::is_in_c40_shift1_set(ch);
|
||||
}
|
||||
|
||||
fn is_in_text_shift2_set( ch: char, fnc1: i32) -> bool {
|
||||
return ::is_in_c40_shift2_set(ch, fnc1);
|
||||
}
|
||||
|
||||
pub fn encode_high_level( msg: &String) -> String {
|
||||
return ::encode_high_level(&msg, null, -1, SymbolShapeHint::FORCE_NONE);
|
||||
}
|
||||
|
||||
pub fn encode_high_level( msg: &String, priority_charset: &Charset, fnc1: i32, shape: &SymbolShapeHint) -> String {
|
||||
let macro_id: i32 = 0;
|
||||
if msg.starts_with(HighLevelEncoder::MACRO_05_HEADER) && msg.ends_with(HighLevelEncoder::MACRO_TRAILER) {
|
||||
macro_id = 5;
|
||||
msg = msg.substring(&HighLevelEncoder::MACRO_05_HEADER::length(), msg.length() - 2);
|
||||
} else if msg.starts_with(HighLevelEncoder::MACRO_06_HEADER) && msg.ends_with(HighLevelEncoder::MACRO_TRAILER) {
|
||||
macro_id = 6;
|
||||
msg = msg.substring(&HighLevelEncoder::MACRO_06_HEADER::length(), msg.length() - 2);
|
||||
}
|
||||
return String::new(&::encode(&msg, &priority_charset, fnc1, shape, macro_id), StandardCharsets::ISO_8859_1);
|
||||
}
|
||||
|
||||
fn encode( input: &String, priority_charset: &Charset, fnc1: i32, shape: &SymbolShapeHint, macro_id: i32) -> Vec<i8> {
|
||||
return ::encode_minimally(Input::new(&input, &priority_charset, fnc1, shape, macro_id)).get_bytes();
|
||||
}
|
||||
|
||||
fn add_edge( edges: &Vec<Vec<Edge>>, edge: &Edge) {
|
||||
let vertex_index: i32 = edge.fromPosition + edge.characterLength;
|
||||
if edges[vertex_index][edge.get_end_mode().ordinal()] == null || edges[vertex_index][edge.get_end_mode().ordinal()].cachedTotalSize > edge.cachedTotalSize {
|
||||
edges[vertex_index][edge.get_end_mode().ordinal()] = edge;
|
||||
}
|
||||
}
|
||||
|
||||
fn get_number_of_c40_words( input: &Input, from: i32, c40: bool, character_length: &Vec<i32>) -> i32 {
|
||||
let thirds_count: i32 = 0;
|
||||
{
|
||||
let mut i: i32 = from;
|
||||
while i < input.length() {
|
||||
{
|
||||
if input.is_e_c_i(i) {
|
||||
character_length[0] = 0;
|
||||
return 0;
|
||||
}
|
||||
let ci: char = input.char_at(i);
|
||||
if c40 && HighLevelEncoder::is_native_c40(ci) || !c40 && HighLevelEncoder::is_native_text(ci) {
|
||||
thirds_count += 1;
|
||||
} else if !::is_extended_a_s_c_i_i(ci, &input.get_f_n_c1_character()) {
|
||||
thirds_count += 2;
|
||||
} else {
|
||||
let ascii_value: i32 = ci & 0xff;
|
||||
if ascii_value >= 128 && (c40 && HighLevelEncoder::is_native_c40((ascii_value - 128) as char) || !c40 && HighLevelEncoder::is_native_text((ascii_value - 128) as char)) {
|
||||
thirds_count += 3;
|
||||
} else {
|
||||
thirds_count += 4;
|
||||
}
|
||||
}
|
||||
if thirds_count % 3 == 0 || ((thirds_count - 2) % 3 == 0 && i + 1 == input.length()) {
|
||||
character_length[0] = i - from + 1;
|
||||
return Math::ceil((thirds_count as f64) / 3.0) as i32;
|
||||
}
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
character_length[0] = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
fn add_edges( input: &Input, edges: &Vec<Vec<Edge>>, from: i32, previous: &Edge) {
|
||||
if input.is_e_c_i(from) {
|
||||
::add_edge(edges, Edge::new(input, Mode::ASCII, from, 1, previous));
|
||||
return;
|
||||
}
|
||||
let ch: char = input.char_at(from);
|
||||
if previous == null || previous.get_end_mode() != Mode::EDF {
|
||||
if HighLevelEncoder::is_digit(ch) && input.have_n_characters(from, 2) && HighLevelEncoder::is_digit(&input.char_at(from + 1)) {
|
||||
::add_edge(edges, Edge::new(input, Mode::ASCII, from, 2, previous));
|
||||
} else {
|
||||
::add_edge(edges, Edge::new(input, Mode::ASCII, from, 1, previous));
|
||||
}
|
||||
let modes: vec![Vec<Mode>; 2] = vec![Mode::C40, Mode::TEXT, ]
|
||||
;
|
||||
for let mode: Mode in modes {
|
||||
let character_length: [i32; 1] = [0; 1];
|
||||
if ::get_number_of_c40_words(input, from, mode == Mode::C40, &character_length) > 0 {
|
||||
::add_edge(edges, Edge::new(input, mode, from, character_length[0], previous));
|
||||
}
|
||||
}
|
||||
if input.have_n_characters(from, 3) && HighLevelEncoder::is_native_x12(&input.char_at(from)) && HighLevelEncoder::is_native_x12(&input.char_at(from + 1)) && HighLevelEncoder::is_native_x12(&input.char_at(from + 2)) {
|
||||
::add_edge(edges, Edge::new(input, Mode::X12, from, 3, previous));
|
||||
}
|
||||
::add_edge(edges, Edge::new(input, Mode::B256, from, 1, previous));
|
||||
}
|
||||
//unless it is 2 characters away from the end of the input.
|
||||
let mut i: i32;
|
||||
{
|
||||
i = 0;
|
||||
while i < 3 {
|
||||
{
|
||||
let pos: i32 = from + i;
|
||||
if input.have_n_characters(pos, 1) && HighLevelEncoder::is_native_e_d_i_f_a_c_t(&input.char_at(pos)) {
|
||||
::add_edge(edges, Edge::new(input, Mode::EDF, from, i + 1, previous));
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
if i == 3 && input.have_n_characters(from, 4) && HighLevelEncoder::is_native_e_d_i_f_a_c_t(&input.char_at(from + 3)) {
|
||||
::add_edge(edges, Edge::new(input, Mode::EDF, from, 4, previous));
|
||||
}
|
||||
}
|
||||
|
||||
fn encode_minimally( input: &Input) -> Result {
|
||||
let input_length: i32 = input.length();
|
||||
// Array that represents vertices. There is a vertex for every character and mode.
|
||||
// The last dimension in the array below encodes the 6 modes ASCII, C40, TEXT, X12, EDF and B256
|
||||
let mut edges: [[Option<Edge>; 6]; input_length + 1] = [[None; 6]; input_length + 1];
|
||||
::add_edges(input, edges, 0, null);
|
||||
{
|
||||
let mut i: i32 = 1;
|
||||
while i <= input_length {
|
||||
{
|
||||
{
|
||||
let mut j: i32 = 0;
|
||||
while j < 6 {
|
||||
{
|
||||
if edges[i][j] != null && i < input_length {
|
||||
::add_edges(input, edges, i, edges[i][j]);
|
||||
}
|
||||
}
|
||||
j += 1;
|
||||
}
|
||||
}
|
||||
|
||||
//optimize memory by removing edges that have been passed.
|
||||
{
|
||||
let mut j: i32 = 0;
|
||||
while j < 6 {
|
||||
{
|
||||
edges[i - 1][j] = null;
|
||||
}
|
||||
j += 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
let minimal_j: i32 = -1;
|
||||
let minimal_size: i32 = Integer::MAX_VALUE;
|
||||
{
|
||||
let mut j: i32 = 0;
|
||||
while j < 6 {
|
||||
{
|
||||
if edges[input_length][j] != null {
|
||||
let edge: Edge = edges[input_length][j];
|
||||
//C40, TEXT and X12 need an
|
||||
let size: i32 = if j >= 1 && j <= 3 { edge.cachedTotalSize + 1 } else { edge.cachedTotalSize };
|
||||
// extra unlatch at the end
|
||||
if size < minimal_size {
|
||||
minimal_size = size;
|
||||
minimal_j = j;
|
||||
}
|
||||
}
|
||||
}
|
||||
j += 1;
|
||||
}
|
||||
}
|
||||
|
||||
if minimal_j < 0 {
|
||||
throw RuntimeException::new(format!("Internal error: failed to encode \"{}\"", input));
|
||||
}
|
||||
return Result::new(edges[input_length][minimal_j]);
|
||||
}
|
||||
|
||||
|
||||
let all_codeword_capacities: vec![Vec<i32>; 28] = vec![3, 5, 8, 10, 12, 16, 18, 22, 30, 32, 36, 44, 49, 62, 86, 114, 144, 174, 204, 280, 368, 456, 576, 696, 816, 1050, 1304, 1558, ]
|
||||
;
|
||||
|
||||
let square_codeword_capacities: vec![Vec<i32>; 24] = vec![3, 5, 8, 12, 18, 22, 30, 36, 44, 62, 86, 114, 144, 174, 204, 280, 368, 456, 576, 696, 816, 1050, 1304, 1558, ]
|
||||
;
|
||||
|
||||
let rectangular_codeword_capacities: vec![Vec<i32>; 6] = vec![5, 10, 16, 33, 32, 49, ]
|
||||
;
|
||||
struct Edge {
|
||||
|
||||
let input: Input;
|
||||
|
||||
//the mode at the start of this edge.
|
||||
let mode: Mode;
|
||||
|
||||
let from_position: i32;
|
||||
|
||||
let character_length: i32;
|
||||
|
||||
let previous: Edge;
|
||||
|
||||
let cached_total_size: i32;
|
||||
}
|
||||
|
||||
impl Edge {
|
||||
|
||||
fn new( input: &Input, mode: &Mode, from_position: i32, character_length: i32, previous: &Edge) -> Edge {
|
||||
let .input = input;
|
||||
let .mode = mode;
|
||||
let .fromPosition = from_position;
|
||||
let .characterLength = character_length;
|
||||
let .previous = previous;
|
||||
assert!( from_position + character_length <= input.length());
|
||||
let mut size: i32 = if previous != null { previous.cachedTotalSize } else { 0 };
|
||||
let previous_mode: Mode = self.get_previous_mode();
|
||||
/*
|
||||
* Switching modes
|
||||
* ASCII -> C40: latch 230
|
||||
* ASCII -> TEXT: latch 239
|
||||
* ASCII -> X12: latch 238
|
||||
* ASCII -> EDF: latch 240
|
||||
* ASCII -> B256: latch 231
|
||||
* C40 -> ASCII: word(c1,c2,c3), 254
|
||||
* TEXT -> ASCII: word(c1,c2,c3), 254
|
||||
* X12 -> ASCII: word(c1,c2,c3), 254
|
||||
* EDIFACT -> ASCII: Unlatch character,0,0,0 or c1,Unlatch character,0,0 or c1,c2,Unlatch character,0 or
|
||||
* c1,c2,c3,Unlatch character
|
||||
* B256 -> ASCII: without latch after n bytes
|
||||
*/
|
||||
match mode {
|
||||
ASCII =>
|
||||
{
|
||||
size += 1;
|
||||
if input.is_e_c_i(from_position) || ::is_extended_a_s_c_i_i(&input.char_at(from_position), &input.get_f_n_c1_character()) {
|
||||
size += 1;
|
||||
}
|
||||
if previous_mode == Mode::C40 || previous_mode == Mode::TEXT || previous_mode == Mode::X12 {
|
||||
// unlatch 254 to ASCII
|
||||
size += 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
B256 =>
|
||||
{
|
||||
size += 1;
|
||||
if previous_mode != Mode::B256 {
|
||||
//byte count
|
||||
size += 1;
|
||||
} else if self.get_b256_size() == 250 {
|
||||
//extra byte count
|
||||
size += 1;
|
||||
}
|
||||
if previous_mode == Mode::ASCII {
|
||||
//latch to B256
|
||||
size += 1;
|
||||
} else if previous_mode == Mode::C40 || previous_mode == Mode::TEXT || previous_mode == Mode::X12 {
|
||||
//unlatch to ASCII, latch to B256
|
||||
size += 2;
|
||||
}
|
||||
break;
|
||||
}
|
||||
C40 =>
|
||||
{
|
||||
}
|
||||
TEXT =>
|
||||
{
|
||||
}
|
||||
X12 =>
|
||||
{
|
||||
if mode == Mode::X12 {
|
||||
size += 2;
|
||||
} else {
|
||||
let char_len: [i32; 1] = [0; 1];
|
||||
size += ::get_number_of_c40_words(input, from_position, mode == Mode::C40, &char_len) * 2;
|
||||
}
|
||||
if previous_mode == Mode::ASCII || previous_mode == Mode::B256 {
|
||||
//additional byte for latch from ASCII to this mode
|
||||
size += 1;
|
||||
} else if previous_mode != mode && (previous_mode == Mode::C40 || previous_mode == Mode::TEXT || previous_mode == Mode::X12) {
|
||||
//unlatch 254 to ASCII followed by latch to this mode
|
||||
size += 2;
|
||||
}
|
||||
break;
|
||||
}
|
||||
EDF =>
|
||||
{
|
||||
size += 3;
|
||||
if previous_mode == Mode::ASCII || previous_mode == Mode::B256 {
|
||||
//additional byte for latch from ASCII to this mode
|
||||
size += 1;
|
||||
} else if previous_mode == Mode::C40 || previous_mode == Mode::TEXT || previous_mode == Mode::X12 {
|
||||
//unlatch 254 to ASCII followed by latch to this mode
|
||||
size += 2;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
cached_total_size = size;
|
||||
}
|
||||
|
||||
// does not count beyond 250
|
||||
fn get_b256_size(&self) -> i32 {
|
||||
let mut cnt: i32 = 0;
|
||||
let mut current: Edge = self;
|
||||
while current != null && current.mode == Mode::B256 && cnt <= 250 {
|
||||
cnt += 1;
|
||||
current = current.previous;
|
||||
}
|
||||
return cnt;
|
||||
}
|
||||
|
||||
fn get_previous_start_mode(&self) -> Mode {
|
||||
return if self.previous == null { Mode::ASCII } else { self.previous.mode };
|
||||
}
|
||||
|
||||
fn get_previous_mode(&self) -> Mode {
|
||||
return if self.previous == null { Mode::ASCII } else { self.previous.get_end_mode() };
|
||||
}
|
||||
|
||||
/** Returns Mode.ASCII in case that:
|
||||
* - Mode is EDIFACT and characterLength is less than 4 or the remaining characters can be encoded in at most 2
|
||||
* ASCII bytes.
|
||||
* - Mode is C40, TEXT or X12 and the remaining characters can be encoded in at most 1 ASCII byte.
|
||||
* Returns mode in all other cases.
|
||||
* */
|
||||
fn get_end_mode(&self) -> Mode {
|
||||
if self.mode == Mode::EDF {
|
||||
if self.character_length < 4 {
|
||||
return Mode::ASCII;
|
||||
}
|
||||
// see 5.2.8.2 EDIFACT encodation Rules
|
||||
let last_a_s_c_i_i: i32 = self.get_last_a_s_c_i_i();
|
||||
if last_a_s_c_i_i > 0 && self.get_codewords_remaining(self.cached_total_size + last_a_s_c_i_i) <= 2 - last_a_s_c_i_i {
|
||||
return Mode::ASCII;
|
||||
}
|
||||
}
|
||||
if self.mode == Mode::C40 || self.mode == Mode::TEXT || self.mode == Mode::X12 {
|
||||
// see 5.2.5.2 C40 encodation rules and 5.2.7.2 ANSI X12 encodation rules
|
||||
if self.from_position + self.character_length >= self.input.length() && self.get_codewords_remaining(self.cached_total_size) == 0 {
|
||||
return Mode::ASCII;
|
||||
}
|
||||
let last_a_s_c_i_i: i32 = self.get_last_a_s_c_i_i();
|
||||
if last_a_s_c_i_i == 1 && self.get_codewords_remaining(self.cached_total_size + 1) == 0 {
|
||||
return Mode::ASCII;
|
||||
}
|
||||
}
|
||||
return self.mode;
|
||||
}
|
||||
|
||||
fn get_mode(&self) -> Mode {
|
||||
return self.mode;
|
||||
}
|
||||
|
||||
/** Peeks ahead and returns 1 if the postfix consists of exactly two digits, 2 if the postfix consists of exactly
|
||||
* two consecutive digits and a non extended character or of 4 digits.
|
||||
* Returns 0 in any other case
|
||||
**/
|
||||
fn get_last_a_s_c_i_i(&self) -> i32 {
|
||||
let length: i32 = self.input.length();
|
||||
let from: i32 = self.from_position + self.character_length;
|
||||
if length - from > 4 || from >= length {
|
||||
return 0;
|
||||
}
|
||||
if length - from == 1 {
|
||||
if ::is_extended_a_s_c_i_i(&self.input.char_at(from), &self.input.get_f_n_c1_character()) {
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
if length - from == 2 {
|
||||
if ::is_extended_a_s_c_i_i(&self.input.char_at(from), &self.input.get_f_n_c1_character()) || ::is_extended_a_s_c_i_i(&self.input.char_at(from + 1), &self.input.get_f_n_c1_character()) {
|
||||
return 0;
|
||||
}
|
||||
if HighLevelEncoder::is_digit(&self.input.char_at(from)) && HighLevelEncoder::is_digit(&self.input.char_at(from + 1)) {
|
||||
return 1;
|
||||
}
|
||||
return 2;
|
||||
}
|
||||
if length - from == 3 {
|
||||
if HighLevelEncoder::is_digit(&self.input.char_at(from)) && HighLevelEncoder::is_digit(&self.input.char_at(from + 1)) && !::is_extended_a_s_c_i_i(&self.input.char_at(from + 2), &self.input.get_f_n_c1_character()) {
|
||||
return 2;
|
||||
}
|
||||
if HighLevelEncoder::is_digit(&self.input.char_at(from + 1)) && HighLevelEncoder::is_digit(&self.input.char_at(from + 2)) && !::is_extended_a_s_c_i_i(&self.input.char_at(from), &self.input.get_f_n_c1_character()) {
|
||||
return 2;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
if HighLevelEncoder::is_digit(&self.input.char_at(from)) && HighLevelEncoder::is_digit(&self.input.char_at(from + 1)) && HighLevelEncoder::is_digit(&self.input.char_at(from + 2)) && HighLevelEncoder::is_digit(&self.input.char_at(from + 3)) {
|
||||
return 2;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Returns the capacity in codewords of the smallest symbol that has enough capacity to fit the given minimal
|
||||
* number of codewords.
|
||||
**/
|
||||
fn get_min_symbol_size(&self, minimum: i32) -> i32 {
|
||||
match self.input.get_shape_hint() {
|
||||
FORCE_SQUARE =>
|
||||
{
|
||||
for let capacity: i32 in square_codeword_capacities {
|
||||
if capacity >= minimum {
|
||||
return capacity;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
FORCE_RECTANGLE =>
|
||||
{
|
||||
for let capacity: i32 in rectangular_codeword_capacities {
|
||||
if capacity >= minimum {
|
||||
return capacity;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
for let capacity: i32 in all_codeword_capacities {
|
||||
if capacity >= minimum {
|
||||
return capacity;
|
||||
}
|
||||
}
|
||||
return all_codeword_capacities[all_codeword_capacities.len() - 1];
|
||||
}
|
||||
|
||||
/** Returns the remaining capacity in codewords of the smallest symbol that has enough capacity to fit the given
|
||||
* minimal number of codewords.
|
||||
**/
|
||||
fn get_codewords_remaining(&self, minimum: i32) -> i32 {
|
||||
return self.get_min_symbol_size(minimum) - minimum;
|
||||
}
|
||||
|
||||
fn get_bytes( c: i32) -> Vec<i8> {
|
||||
let mut result: [i8; 1] = [0; 1];
|
||||
result[0] = c as i8;
|
||||
return result;
|
||||
}
|
||||
|
||||
fn get_bytes( c1: i32, c2: i32) -> Vec<i8> {
|
||||
let mut result: [i8; 2] = [0; 2];
|
||||
result[0] = c1 as i8;
|
||||
result[1] = c2 as i8;
|
||||
return result;
|
||||
}
|
||||
|
||||
fn set_c40_word( bytes: &Vec<i8>, offset: i32, c1: i32, c2: i32, c3: i32) {
|
||||
let val16: i32 = (1600 * (c1 & 0xff)) + (40 * (c2 & 0xff)) + (c3 & 0xff) + 1;
|
||||
bytes[offset] = (val16 / 256) as i8;
|
||||
bytes[offset + 1] = (val16 % 256) as i8;
|
||||
}
|
||||
|
||||
fn get_x12_value( c: char) -> i32 {
|
||||
return if c == 13 { 0 } else { if c == 42 { 1 } else { if c == 62 { 2 } else { if c == 32 { 3 } else { if c >= 48 && c <= 57 { c - 44 } else { if c >= 65 && c <= 90 { c - 51 } else { c } } } } } };
|
||||
}
|
||||
|
||||
fn get_x12_words(&self) -> Vec<i8> {
|
||||
assert!( self.character_length % 3 == 0);
|
||||
let result: [i8; self.character_length / 3 * 2] = [0; self.character_length / 3 * 2];
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < result.len() {
|
||||
{
|
||||
::set_c40_word(&result, i, &::get_x12_value(&self.input.char_at(self.from_position + i / 2 * 3)), &::get_x12_value(&self.input.char_at(self.from_position + i / 2 * 3 + 1)), &::get_x12_value(&self.input.char_at(self.from_position + i / 2 * 3 + 2)));
|
||||
}
|
||||
i += 2;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
fn get_shift_value( c: char, c40: bool, fnc1: i32) -> i32 {
|
||||
return if (c40 && ::is_in_c40_shift1_set(c) || !c40 && ::is_in_text_shift1_set(c)) { 0 } else { if (c40 && ::is_in_c40_shift2_set(c, fnc1) || !c40 && ::is_in_text_shift2_set(c, fnc1)) { 1 } else { 2 } };
|
||||
}
|
||||
|
||||
fn get_c40_value( c40: bool, set_index: i32, c: char, fnc1: i32) -> i32 {
|
||||
if c == fnc1 {
|
||||
assert!( set_index == 2);
|
||||
return 27;
|
||||
}
|
||||
if c40 {
|
||||
return if c <= 31 { c } else { if c == 32 { 3 } else { if c <= 47 { c - 33 } else { if c <= 57 { c - 44 } else { if c <= 64 { c - 43 } else { if c <= 90 { c - 51 } else { if c <= 95 { c - 69 } else { if c <= 127 { c - 96 } else { c } } } } } } } };
|
||||
} else {
|
||||
return if c == 0 { 0 } else { if //is this a bug in the spec?
|
||||
set_index == 0 && c <= 3 { //is this a bug in the spec?
|
||||
c - 1 } else { if set_index == 1 && c <= 31 { c } else { if c == 32 { 3 } else { if c >= 33 && c <= 47 { c - 33 } else { if c >= 48 && c <= 57 { c - 44 } else { if c >= 58 && c <= 64 { c - 43 } else { if c >= 65 && c <= 90 { c - 64 } else { if c >= 91 && c <= 95 { c - 69 } else { if c == 96 { 0 } else { if c >= 97 && c <= 122 { c - 83 } else { if c >= 123 && c <= 127 { c - 96 } else { c } } } } } } } } } } } };
|
||||
}
|
||||
}
|
||||
|
||||
fn get_c40_words(&self, c40: bool, fnc1: i32) -> Vec<i8> {
|
||||
let c40_values: List<Byte> = ArrayList<>::new();
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < self.character_length {
|
||||
{
|
||||
let ci: char = self.input.char_at(self.from_position + i);
|
||||
if c40 && HighLevelEncoder::is_native_c40(ci) || !c40 && HighLevelEncoder::is_native_text(ci) {
|
||||
c40_values.add(::get_c40_value(c40, 0, ci, fnc1) as i8);
|
||||
} else if !::is_extended_a_s_c_i_i(ci, fnc1) {
|
||||
let shift_value: i32 = ::get_shift_value(ci, c40, fnc1);
|
||||
//Shift[123]
|
||||
c40_values.add(shift_value as i8);
|
||||
c40_values.add(::get_c40_value(c40, shift_value, ci, fnc1) as i8);
|
||||
} else {
|
||||
let ascii_value: char = ((ci & 0xff) - 128) as char;
|
||||
if c40 && HighLevelEncoder::is_native_c40(ascii_value) || !c40 && HighLevelEncoder::is_native_text(ascii_value) {
|
||||
//Shift 2
|
||||
c40_values.add(1 as i8);
|
||||
//Upper Shift
|
||||
c40_values.add(30 as i8);
|
||||
c40_values.add(::get_c40_value(c40, 0, ascii_value, fnc1) as i8);
|
||||
} else {
|
||||
//Shift 2
|
||||
c40_values.add(1 as i8);
|
||||
//Upper Shift
|
||||
c40_values.add(30 as i8);
|
||||
let shift_value: i32 = ::get_shift_value(ascii_value, c40, fnc1);
|
||||
// Shift[123]
|
||||
c40_values.add(shift_value as i8);
|
||||
c40_values.add(::get_c40_value(c40, shift_value, ascii_value, fnc1) as i8);
|
||||
}
|
||||
}
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (c40_values.size() % 3) != 0 {
|
||||
assert!( (c40_values.size() - 2) % 3 == 0 && self.from_position + self.character_length == self.input.length());
|
||||
// pad with 0 (Shift 1)
|
||||
c40_values.add(0 as i8);
|
||||
}
|
||||
let result: [i8; c40_values.size() / 3 * 2] = [0; c40_values.size() / 3 * 2];
|
||||
let byte_index: i32 = 0;
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < c40_values.size() {
|
||||
{
|
||||
::set_c40_word(&result, byte_index, c40_values.get(i) & 0xff, c40_values.get(i + 1) & 0xff, c40_values.get(i + 2) & 0xff);
|
||||
byte_index += 2;
|
||||
}
|
||||
i += 3;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
fn get_e_d_f_bytes(&self) -> Vec<i8> {
|
||||
let number_of_thirds: i32 = Math::ceil(self.character_length / 4.0) as i32;
|
||||
let mut result: [i8; number_of_thirds * 3] = [0; number_of_thirds * 3];
|
||||
let mut pos: i32 = self.from_position;
|
||||
let end_pos: i32 = Math::min(self.from_position + self.character_length - 1, self.input.length() - 1);
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < number_of_thirds {
|
||||
{
|
||||
let edf_values: [i32; 4] = [0; 4];
|
||||
{
|
||||
let mut j: i32 = 0;
|
||||
while j < 4 {
|
||||
{
|
||||
if pos <= end_pos {
|
||||
edf_values[j] = self.input.char_at(pos += 1 !!!check!!! post increment) & 0x3f;
|
||||
} else {
|
||||
edf_values[j] = if pos == end_pos + 1 { 0x1f } else { 0 };
|
||||
}
|
||||
}
|
||||
j += 1;
|
||||
}
|
||||
}
|
||||
|
||||
let mut val24: i32 = edf_values[0] << 18;
|
||||
val24 |= edf_values[1] << 12;
|
||||
val24 |= edf_values[2] << 6;
|
||||
val24 |= edf_values[3];
|
||||
result[i] = ((val24 >> 16) & 0xff) as i8;
|
||||
result[i + 1] = ((val24 >> 8) & 0xff) as i8;
|
||||
result[i + 2] = (val24 & 0xff) as i8;
|
||||
}
|
||||
i += 3;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
fn get_latch_bytes(&self) -> Vec<i8> {
|
||||
match self.get_previous_mode() {
|
||||
ASCII =>
|
||||
{
|
||||
}
|
||||
//after B256 ends (via length) we are back to ASCII
|
||||
B256 =>
|
||||
{
|
||||
match self.mode {
|
||||
B256 =>
|
||||
{
|
||||
return ::get_bytes(231);
|
||||
}
|
||||
C40 =>
|
||||
{
|
||||
return ::get_bytes(230);
|
||||
}
|
||||
TEXT =>
|
||||
{
|
||||
return ::get_bytes(239);
|
||||
}
|
||||
X12 =>
|
||||
{
|
||||
return ::get_bytes(238);
|
||||
}
|
||||
EDF =>
|
||||
{
|
||||
return ::get_bytes(240);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
C40 =>
|
||||
{
|
||||
}
|
||||
TEXT =>
|
||||
{
|
||||
}
|
||||
X12 =>
|
||||
{
|
||||
if self.mode != self.get_previous_mode() {
|
||||
match self.mode {
|
||||
ASCII =>
|
||||
{
|
||||
return ::get_bytes(254);
|
||||
}
|
||||
B256 =>
|
||||
{
|
||||
return ::get_bytes(254, 231);
|
||||
}
|
||||
C40 =>
|
||||
{
|
||||
return ::get_bytes(254, 230);
|
||||
}
|
||||
TEXT =>
|
||||
{
|
||||
return ::get_bytes(254, 239);
|
||||
}
|
||||
X12 =>
|
||||
{
|
||||
return ::get_bytes(254, 238);
|
||||
}
|
||||
EDF =>
|
||||
{
|
||||
return ::get_bytes(254, 240);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
EDF =>
|
||||
{
|
||||
//The rightmost EDIFACT edge always contains an unlatch character
|
||||
assert!( self.mode == Mode::EDF);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return : [i8; 0] = [0; 0];
|
||||
}
|
||||
|
||||
// Important: The function does not return the length bytes (one or two) in case of B256 encoding
|
||||
fn get_data_bytes(&self) -> Vec<i8> {
|
||||
match self.mode {
|
||||
ASCII =>
|
||||
{
|
||||
if self.input.is_e_c_i(self.from_position) {
|
||||
return ::get_bytes(241, self.input.get_e_c_i_value(self.from_position) + 1);
|
||||
} else if ::is_extended_a_s_c_i_i(&self.input.char_at(self.from_position), &self.input.get_f_n_c1_character()) {
|
||||
return ::get_bytes(235, self.input.char_at(self.from_position) - 127);
|
||||
} else if self.character_length == 2 {
|
||||
return ::get_bytes((self.input.char_at(self.from_position) - '0') * 10 + self.input.char_at(self.from_position + 1) - '0' + 130);
|
||||
} else if self.input.is_f_n_c1(self.from_position) {
|
||||
return ::get_bytes(232);
|
||||
} else {
|
||||
return ::get_bytes(self.input.char_at(self.from_position) + 1);
|
||||
}
|
||||
}
|
||||
B256 =>
|
||||
{
|
||||
return ::get_bytes(&self.input.char_at(self.from_position));
|
||||
}
|
||||
C40 =>
|
||||
{
|
||||
return self.get_c40_words(true, &self.input.get_f_n_c1_character());
|
||||
}
|
||||
TEXT =>
|
||||
{
|
||||
return self.get_c40_words(false, &self.input.get_f_n_c1_character());
|
||||
}
|
||||
X12 =>
|
||||
{
|
||||
return self.get_x12_words();
|
||||
}
|
||||
EDF =>
|
||||
{
|
||||
return self.get_e_d_f_bytes();
|
||||
}
|
||||
}
|
||||
assert!( false);
|
||||
return : [i8; 0] = [0; 0];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
struct Result {
|
||||
|
||||
let mut bytes: Vec<i8>;
|
||||
}
|
||||
|
||||
impl Result {
|
||||
|
||||
fn new( solution: &Edge) -> Result {
|
||||
let input: Input = solution.input;
|
||||
let mut size: i32 = 0;
|
||||
let bytes_a_l: List<Byte> = ArrayList<>::new();
|
||||
let randomize_postfix_length: List<Integer> = ArrayList<>::new();
|
||||
let randomize_lengths: List<Integer> = ArrayList<>::new();
|
||||
if (solution.mode == Mode::C40 || solution.mode == Mode::TEXT || solution.mode == Mode::X12) && solution.get_end_mode() != Mode::ASCII {
|
||||
size += ::prepend(&MinimalEncoder::Edge::get_bytes(254), &bytes_a_l);
|
||||
}
|
||||
let mut current: Edge = solution;
|
||||
while current != null {
|
||||
size += ::prepend(¤t.get_data_bytes(), &bytes_a_l);
|
||||
if current.previous == null || current.get_previous_start_mode() != current.get_mode() {
|
||||
if current.get_mode() == Mode::B256 {
|
||||
if size <= 249 {
|
||||
bytes_a_l.add(0, size as i8);
|
||||
size += 1;
|
||||
} else {
|
||||
bytes_a_l.add(0, (size % 250) as i8);
|
||||
bytes_a_l.add(0, (size / 250 + 249) as i8);
|
||||
size += 2;
|
||||
}
|
||||
randomize_postfix_length.add(&bytes_a_l.size());
|
||||
randomize_lengths.add(size);
|
||||
}
|
||||
::prepend(¤t.get_latch_bytes(), &bytes_a_l);
|
||||
size = 0;
|
||||
}
|
||||
current = current.previous;
|
||||
}
|
||||
if input.get_macro_id() == 5 {
|
||||
size += ::prepend(&MinimalEncoder::Edge::get_bytes(236), &bytes_a_l);
|
||||
} else if input.get_macro_id() == 6 {
|
||||
size += ::prepend(&MinimalEncoder::Edge::get_bytes(237), &bytes_a_l);
|
||||
}
|
||||
if input.get_f_n_c1_character() > 0 {
|
||||
size += ::prepend(&MinimalEncoder::Edge::get_bytes(232), &bytes_a_l);
|
||||
}
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < randomize_postfix_length.size() {
|
||||
{
|
||||
::apply_random_pattern(&bytes_a_l, bytes_a_l.size() - randomize_postfix_length.get(i), &randomize_lengths.get(i));
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
//add padding
|
||||
let capacity: i32 = solution.get_min_symbol_size(&bytes_a_l.size());
|
||||
if bytes_a_l.size() < capacity {
|
||||
bytes_a_l.add(129 as i8);
|
||||
}
|
||||
while bytes_a_l.size() < capacity {
|
||||
bytes_a_l.add(::randomize253_state(bytes_a_l.size() + 1) as i8);
|
||||
}
|
||||
bytes = : [i8; bytes_a_l.size()] = [0; bytes_a_l.size()];
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < bytes.len() {
|
||||
{
|
||||
bytes[i] = bytes_a_l.get(i);
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fn prepend( bytes: &Vec<i8>, into: &List<Byte>) -> i32 {
|
||||
{
|
||||
let mut i: i32 = bytes.len() - 1;
|
||||
while i >= 0 {
|
||||
{
|
||||
into.add(0, bytes[i]);
|
||||
}
|
||||
i -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
return bytes.len();
|
||||
}
|
||||
|
||||
fn randomize253_state( codeword_position: i32) -> i32 {
|
||||
let pseudo_random: i32 = ((149 * codeword_position) % 253) + 1;
|
||||
let temp_variable: i32 = 129 + pseudo_random;
|
||||
return if temp_variable <= 254 { temp_variable } else { temp_variable - 254 };
|
||||
}
|
||||
|
||||
fn apply_random_pattern( bytes_a_l: &List<Byte>, start_position: i32, length: i32) {
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < length {
|
||||
{
|
||||
//See "B.1 253-state algorithm
|
||||
const Pad_codeword_position: i32 = start_position + i;
|
||||
const Pad_codeword_value: i32 = bytes_a_l.get(Pad_codeword_position) & 0xff;
|
||||
let pseudo_random_number: i32 = ((149 * (Pad_codeword_position + 1)) % 255) + 1;
|
||||
let temp_variable: i32 = Pad_codeword_value + pseudo_random_number;
|
||||
bytes_a_l.set(Pad_codeword_position, ( if temp_variable <= 255 { temp_variable } else { temp_variable - 256 }) as i8);
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
pub fn get_bytes(&self) -> Vec<i8> {
|
||||
return self.bytes;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
struct Input {
|
||||
super: MinimalECIInput;
|
||||
|
||||
let shape: SymbolShapeHint;
|
||||
|
||||
let macro_id: i32;
|
||||
}
|
||||
|
||||
impl Input {
|
||||
|
||||
fn new( string_to_encode: &String, priority_charset: &Charset, fnc1: i32, shape: &SymbolShapeHint, macro_id: i32) -> Input {
|
||||
super(&string_to_encode, &priority_charset, fnc1);
|
||||
let .shape = shape;
|
||||
let .macroId = macro_id;
|
||||
}
|
||||
|
||||
fn get_macro_id(&self) -> i32 {
|
||||
return self.macro_id;
|
||||
}
|
||||
|
||||
fn get_shape_hint(&self) -> SymbolShapeHint {
|
||||
return self.shape;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
220
port_src/output/zxing/datamatrix/encoder/symbol_info.rs
Normal file
220
port_src/output/zxing/datamatrix/encoder/symbol_info.rs
Normal file
@@ -0,0 +1,220 @@
|
||||
/*
|
||||
* Copyright 2006 Jeremias Maerki
|
||||
*
|
||||
* 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::datamatrix::encoder;
|
||||
|
||||
/**
|
||||
* Symbol info table for DataMatrix.
|
||||
*
|
||||
* @version $Id$
|
||||
*/
|
||||
|
||||
const PROD_SYMBOLS: vec![Vec<SymbolInfo>; 30] = vec![SymbolInfo::new(false, 3, 5, 8, 8, 1), SymbolInfo::new(false, 5, 7, 10, 10, 1), /*rect*/
|
||||
SymbolInfo::new(true, 5, 7, 16, 6, 1), SymbolInfo::new(false, 8, 10, 12, 12, 1), /*rect*/
|
||||
SymbolInfo::new(true, 10, 11, 14, 6, 2), SymbolInfo::new(false, 12, 12, 14, 14, 1), /*rect*/
|
||||
SymbolInfo::new(true, 16, 14, 24, 10, 1), SymbolInfo::new(false, 18, 14, 16, 16, 1), SymbolInfo::new(false, 22, 18, 18, 18, 1), /*rect*/
|
||||
SymbolInfo::new(true, 22, 18, 16, 10, 2), SymbolInfo::new(false, 30, 20, 20, 20, 1), /*rect*/
|
||||
SymbolInfo::new(true, 32, 24, 16, 14, 2), SymbolInfo::new(false, 36, 24, 22, 22, 1), SymbolInfo::new(false, 44, 28, 24, 24, 1), /*rect*/
|
||||
SymbolInfo::new(true, 49, 28, 22, 14, 2), SymbolInfo::new(false, 62, 36, 14, 14, 4), SymbolInfo::new(false, 86, 42, 16, 16, 4), SymbolInfo::new(false, 114, 48, 18, 18, 4), SymbolInfo::new(false, 144, 56, 20, 20, 4), SymbolInfo::new(false, 174, 68, 22, 22, 4), SymbolInfo::new(false, 204, 84, 24, 24, 4, 102, 42), SymbolInfo::new(false, 280, 112, 14, 14, 16, 140, 56), SymbolInfo::new(false, 368, 144, 16, 16, 16, 92, 36), SymbolInfo::new(false, 456, 192, 18, 18, 16, 114, 48), SymbolInfo::new(false, 576, 224, 20, 20, 16, 144, 56), SymbolInfo::new(false, 696, 272, 22, 22, 16, 174, 68), SymbolInfo::new(false, 816, 336, 24, 24, 16, 136, 56), SymbolInfo::new(false, 1050, 408, 18, 18, 36, 175, 68), SymbolInfo::new(false, 1304, 496, 20, 20, 36, 163, 62), DataMatrixSymbolInfo144::new(), ]
|
||||
;
|
||||
|
||||
let mut symbols: Vec<SymbolInfo> = PROD_SYMBOLS;
|
||||
pub struct SymbolInfo {
|
||||
|
||||
let rectangular: bool;
|
||||
|
||||
let data_capacity: i32;
|
||||
|
||||
let error_codewords: i32;
|
||||
|
||||
let matrix_width: i32;
|
||||
|
||||
let matrix_height: i32;
|
||||
|
||||
let data_regions: i32;
|
||||
|
||||
let rs_block_data: i32;
|
||||
|
||||
let rs_block_error: i32;
|
||||
}
|
||||
|
||||
impl SymbolInfo {
|
||||
|
||||
/**
|
||||
* Overrides the symbol info set used by this class. Used for testing purposes.
|
||||
*
|
||||
* @param override the symbol info set to use
|
||||
*/
|
||||
pub fn override_symbol_set( override: &Vec<SymbolInfo>) {
|
||||
symbols = override;
|
||||
}
|
||||
|
||||
pub fn new( rectangular: bool, data_capacity: i32, error_codewords: i32, matrix_width: i32, matrix_height: i32, data_regions: i32) -> SymbolInfo {
|
||||
this(rectangular, data_capacity, error_codewords, matrix_width, matrix_height, data_regions, data_capacity, error_codewords);
|
||||
}
|
||||
|
||||
fn new( rectangular: bool, data_capacity: i32, error_codewords: i32, matrix_width: i32, matrix_height: i32, data_regions: i32, rs_block_data: i32, rs_block_error: i32) -> SymbolInfo {
|
||||
let .rectangular = rectangular;
|
||||
let .dataCapacity = data_capacity;
|
||||
let .errorCodewords = error_codewords;
|
||||
let .matrixWidth = matrix_width;
|
||||
let .matrixHeight = matrix_height;
|
||||
let .dataRegions = data_regions;
|
||||
let .rsBlockData = rs_block_data;
|
||||
let .rsBlockError = rs_block_error;
|
||||
}
|
||||
|
||||
pub fn lookup( data_codewords: i32) -> SymbolInfo {
|
||||
return ::lookup(data_codewords, SymbolShapeHint::FORCE_NONE, true);
|
||||
}
|
||||
|
||||
pub fn lookup( data_codewords: i32, shape: &SymbolShapeHint) -> SymbolInfo {
|
||||
return ::lookup(data_codewords, shape, true);
|
||||
}
|
||||
|
||||
pub fn lookup( data_codewords: i32, allow_rectangular: bool, fail: bool) -> SymbolInfo {
|
||||
let shape: SymbolShapeHint = if allow_rectangular { SymbolShapeHint::FORCE_NONE } else { SymbolShapeHint::FORCE_SQUARE };
|
||||
return ::lookup(data_codewords, shape, fail);
|
||||
}
|
||||
|
||||
fn lookup( data_codewords: i32, shape: &SymbolShapeHint, fail: bool) -> SymbolInfo {
|
||||
return ::lookup(data_codewords, shape, null, null, fail);
|
||||
}
|
||||
|
||||
pub fn lookup( data_codewords: i32, shape: &SymbolShapeHint, min_size: &Dimension, max_size: &Dimension, fail: bool) -> SymbolInfo {
|
||||
for let symbol: SymbolInfo in symbols {
|
||||
if shape == SymbolShapeHint::FORCE_SQUARE && symbol.rectangular {
|
||||
continue;
|
||||
}
|
||||
if shape == SymbolShapeHint::FORCE_RECTANGLE && !symbol.rectangular {
|
||||
continue;
|
||||
}
|
||||
if min_size != null && (symbol.get_symbol_width() < min_size.get_width() || symbol.get_symbol_height() < min_size.get_height()) {
|
||||
continue;
|
||||
}
|
||||
if max_size != null && (symbol.get_symbol_width() > max_size.get_width() || symbol.get_symbol_height() > max_size.get_height()) {
|
||||
continue;
|
||||
}
|
||||
if data_codewords <= symbol.dataCapacity {
|
||||
return symbol;
|
||||
}
|
||||
}
|
||||
if fail {
|
||||
throw IllegalArgumentException::new(format!("Can't find a symbol arrangement that matches the message. Data codewords: {}", data_codewords));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
fn get_horizontal_data_regions(&self) -> i32 {
|
||||
match self.data_regions {
|
||||
1 =>
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
2 =>
|
||||
{
|
||||
}
|
||||
4 =>
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
16 =>
|
||||
{
|
||||
return 4;
|
||||
}
|
||||
36 =>
|
||||
{
|
||||
return 6;
|
||||
}
|
||||
_ =>
|
||||
{
|
||||
throw IllegalStateException::new("Cannot handle this number of data regions");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn get_vertical_data_regions(&self) -> i32 {
|
||||
match self.data_regions {
|
||||
1 =>
|
||||
{
|
||||
}
|
||||
2 =>
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
4 =>
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
16 =>
|
||||
{
|
||||
return 4;
|
||||
}
|
||||
36 =>
|
||||
{
|
||||
return 6;
|
||||
}
|
||||
_ =>
|
||||
{
|
||||
throw IllegalStateException::new("Cannot handle this number of data regions");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_symbol_data_width(&self) -> i32 {
|
||||
return self.get_horizontal_data_regions() * self.matrix_width;
|
||||
}
|
||||
|
||||
pub fn get_symbol_data_height(&self) -> i32 {
|
||||
return self.get_vertical_data_regions() * self.matrix_height;
|
||||
}
|
||||
|
||||
pub fn get_symbol_width(&self) -> i32 {
|
||||
return self.get_symbol_data_width() + (self.get_horizontal_data_regions() * 2);
|
||||
}
|
||||
|
||||
pub fn get_symbol_height(&self) -> i32 {
|
||||
return self.get_symbol_data_height() + (self.get_vertical_data_regions() * 2);
|
||||
}
|
||||
|
||||
pub fn get_codeword_count(&self) -> i32 {
|
||||
return self.data_capacity + self.error_codewords;
|
||||
}
|
||||
|
||||
pub fn get_interleaved_block_count(&self) -> i32 {
|
||||
return self.data_capacity / self.rs_block_data;
|
||||
}
|
||||
|
||||
pub fn get_data_capacity(&self) -> i32 {
|
||||
return self.data_capacity;
|
||||
}
|
||||
|
||||
pub fn get_error_codewords(&self) -> i32 {
|
||||
return self.error_codewords;
|
||||
}
|
||||
|
||||
pub fn get_data_length_for_interleaved_block(&self, index: i32) -> i32 {
|
||||
return self.rs_block_data;
|
||||
}
|
||||
|
||||
pub fn get_error_length_for_interleaved_block(&self, index: i32) -> i32 {
|
||||
return self.rs_block_error;
|
||||
}
|
||||
|
||||
pub fn to_string(&self) -> String {
|
||||
return format!("{} data region {}x{}, symbol size {}x{}, symbol data size {}x{}, codewords {}+{}", ( if self.rectangular { "Rectangular Symbol:" } else { "Square Symbol:" }), self.matrix_width, self.matrix_height, self.get_symbol_width(), self.get_symbol_height(), self.get_symbol_data_width(), self.get_symbol_data_height(), self.data_capacity, self.error_codewords);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright 2007 Jeremias Maerki.
|
||||
*
|
||||
* 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::datamatrix::encoder;
|
||||
|
||||
/**
|
||||
* Enumeration for DataMatrix symbol shape hint. It can be used to force square or rectangular
|
||||
* symbols.
|
||||
*/
|
||||
pub enum SymbolShapeHint {
|
||||
|
||||
FORCE_NONE(), FORCE_SQUARE(), FORCE_RECTANGLE()
|
||||
}
|
||||
91
port_src/output/zxing/datamatrix/encoder/text_encoder.rs
Normal file
91
port_src/output/zxing/datamatrix/encoder/text_encoder.rs
Normal file
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Copyright 2006-2007 Jeremias Maerki.
|
||||
*
|
||||
* 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::datamatrix::encoder;
|
||||
|
||||
struct TextEncoder {
|
||||
super: C40Encoder;
|
||||
}
|
||||
|
||||
impl TextEncoder {
|
||||
|
||||
pub fn get_encoding_mode(&self) -> i32 {
|
||||
return HighLevelEncoder::TEXT_ENCODATION;
|
||||
}
|
||||
|
||||
fn encode_char(&self, c: char, sb: &StringBuilder) -> i32 {
|
||||
if c == ' ' {
|
||||
sb.append('\3');
|
||||
return 1;
|
||||
}
|
||||
if c >= '0' && c <= '9' {
|
||||
sb.append((c - 48 + 4) as char);
|
||||
return 1;
|
||||
}
|
||||
if c >= 'a' && c <= 'z' {
|
||||
sb.append((c - 97 + 14) as char);
|
||||
return 1;
|
||||
}
|
||||
if c < ' ' {
|
||||
//Shift 1 Set
|
||||
sb.append('\0');
|
||||
sb.append(c);
|
||||
return 2;
|
||||
}
|
||||
if c <= '/' {
|
||||
//Shift 2 Set
|
||||
sb.append('\1');
|
||||
sb.append((c - 33) as char);
|
||||
return 2;
|
||||
}
|
||||
if c <= '@' {
|
||||
//Shift 2 Set
|
||||
sb.append('\1');
|
||||
sb.append((c - 58 + 15) as char);
|
||||
return 2;
|
||||
}
|
||||
if c >= '[' && c <= '_' {
|
||||
//Shift 2 Set
|
||||
sb.append('\1');
|
||||
sb.append((c - 91 + 22) as char);
|
||||
return 2;
|
||||
}
|
||||
if c == '`' {
|
||||
//Shift 3 Set
|
||||
sb.append('\2');
|
||||
// '`' - 96 == 0
|
||||
sb.append(0 as char);
|
||||
return 2;
|
||||
}
|
||||
if c <= 'Z' {
|
||||
//Shift 3 Set
|
||||
sb.append('\2');
|
||||
sb.append((c - 65 + 1) as char);
|
||||
return 2;
|
||||
}
|
||||
if c <= 127 {
|
||||
//Shift 3 Set
|
||||
sb.append('\2');
|
||||
sb.append((c - 123 + 27) as char);
|
||||
return 2;
|
||||
}
|
||||
//Shift 2, Upper Shift
|
||||
sb.append("\1");
|
||||
let mut len: i32 = 2;
|
||||
len += self.encode_char((c - 128) as char, &sb);
|
||||
return len;
|
||||
}
|
||||
}
|
||||
|
||||
99
port_src/output/zxing/datamatrix/encoder/x12_encoder.rs
Normal file
99
port_src/output/zxing/datamatrix/encoder/x12_encoder.rs
Normal file
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* Copyright 2006-2007 Jeremias Maerki.
|
||||
*
|
||||
* 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::datamatrix::encoder;
|
||||
|
||||
struct X12Encoder {
|
||||
super: C40Encoder;
|
||||
}
|
||||
|
||||
impl X12Encoder {
|
||||
|
||||
pub fn get_encoding_mode(&self) -> i32 {
|
||||
return HighLevelEncoder::X12_ENCODATION;
|
||||
}
|
||||
|
||||
pub fn encode(&self, context: &EncoderContext) {
|
||||
//step C
|
||||
let buffer: StringBuilder = StringBuilder::new();
|
||||
while context.has_more_characters() {
|
||||
let c: char = context.get_current_char();
|
||||
context.pos += 1;
|
||||
self.encode_char(c, &buffer);
|
||||
let count: i32 = buffer.length();
|
||||
if (count % 3) == 0 {
|
||||
write_next_triplet(context, &buffer);
|
||||
let new_mode: i32 = HighLevelEncoder::look_ahead_test(&context.get_message(), context.pos, &self.get_encoding_mode());
|
||||
if new_mode != self.get_encoding_mode() {
|
||||
// Return to ASCII encodation, which will actually handle latch to new mode
|
||||
context.signal_encoder_change(HighLevelEncoder::ASCII_ENCODATION);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
self.handle_e_o_d(context, &buffer);
|
||||
}
|
||||
|
||||
fn encode_char(&self, c: char, sb: &StringBuilder) -> i32 {
|
||||
match c {
|
||||
'\r' =>
|
||||
{
|
||||
sb.append('\0');
|
||||
break;
|
||||
}
|
||||
'*' =>
|
||||
{
|
||||
sb.append('\1');
|
||||
break;
|
||||
}
|
||||
'>' =>
|
||||
{
|
||||
sb.append('\2');
|
||||
break;
|
||||
}
|
||||
' ' =>
|
||||
{
|
||||
sb.append('\3');
|
||||
break;
|
||||
}
|
||||
_ =>
|
||||
{
|
||||
if c >= '0' && c <= '9' {
|
||||
sb.append((c - 48 + 4) as char);
|
||||
} else if c >= 'A' && c <= 'Z' {
|
||||
sb.append((c - 65 + 14) as char);
|
||||
} else {
|
||||
HighLevelEncoder::illegal_character(c);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
fn handle_e_o_d(&self, context: &EncoderContext, buffer: &StringBuilder) {
|
||||
context.update_symbol_info();
|
||||
let available: i32 = context.get_symbol_info().get_data_capacity() - context.get_codeword_count();
|
||||
let count: i32 = buffer.length();
|
||||
context.pos -= count;
|
||||
if context.get_remaining_characters() > 1 || available > 1 || context.get_remaining_characters() != available {
|
||||
context.write_codeword(HighLevelEncoder::X12_UNLATCH);
|
||||
}
|
||||
if context.get_new_encoding() < 0 {
|
||||
context.signal_encoder_change(HighLevelEncoder::ASCII_ENCODATION);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user