@@ -32,6 +32,7 @@ resvg = {version = "0.35", optional = true, default-features=false}
|
|||||||
serde = { version = "1.0", features = ["derive", "rc"], optional = true }
|
serde = { version = "1.0", features = ["derive", "rc"], optional = true }
|
||||||
thiserror = "1.0.44"
|
thiserror = "1.0.44"
|
||||||
multimap = "0.9"
|
multimap = "0.9"
|
||||||
|
bit_reverse = "0.1.8"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
java-properties = "2.0"
|
java-properties = "2.0"
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ use rxing::multi::{GenericMultipleBarcodeReader, MultipleBarcodeReader};
|
|||||||
use rxing::oned::rss::expanded::RSSExpandedReader;
|
use rxing::oned::rss::expanded::RSSExpandedReader;
|
||||||
use rxing::oned::rss::RSS14Reader;
|
use rxing::oned::rss::RSS14Reader;
|
||||||
use rxing::oned::{
|
use rxing::oned::{
|
||||||
CodaBarReader, Code39Reader, Code93Reader, EAN13Reader, EAN8Reader, ITFReader, UPCAReader,
|
CodaBarReader, Code39Reader, Code93Reader, EAN13Reader, EAN8Reader, TelepenReader, ITFReader, UPCAReader,
|
||||||
UPCEReader,
|
UPCEReader,
|
||||||
};
|
};
|
||||||
use rxing::pdf417::PDF417Reader;
|
use rxing::pdf417::PDF417Reader;
|
||||||
@@ -165,6 +165,17 @@ fn rss_expanded_benchmark(c: &mut Criterion) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn telepen_benchmark(c: &mut Criterion) {
|
||||||
|
let mut image = get_image("test_resources/blackbox/telepen-1/02.png");
|
||||||
|
let mut reader = TelepenReader::default();
|
||||||
|
|
||||||
|
c.bench_function("telepen", |b| {
|
||||||
|
b.iter(|| {
|
||||||
|
let _res = reader.decode(&mut image);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
fn upca_benchmark(c: &mut Criterion) {
|
fn upca_benchmark(c: &mut Criterion) {
|
||||||
let mut image = get_image("test_resources/blackbox/upca-4/1.png");
|
let mut image = get_image("test_resources/blackbox/upca-4/1.png");
|
||||||
c.bench_function("upca", |b| {
|
c.bench_function("upca", |b| {
|
||||||
@@ -210,6 +221,7 @@ criterion_group!(
|
|||||||
qrcode_benchmark,
|
qrcode_benchmark,
|
||||||
rss14_benchmark,
|
rss14_benchmark,
|
||||||
rss_expanded_benchmark,
|
rss_expanded_benchmark,
|
||||||
|
telepen_benchmark,
|
||||||
upca_benchmark,
|
upca_benchmark,
|
||||||
upce_benchmark,
|
upce_benchmark,
|
||||||
multi_barcode_benchmark
|
multi_barcode_benchmark
|
||||||
|
|||||||
@@ -73,6 +73,9 @@ pub enum BarcodeFormat {
|
|||||||
/** RSS EXPANDED */
|
/** RSS EXPANDED */
|
||||||
RSS_EXPANDED,
|
RSS_EXPANDED,
|
||||||
|
|
||||||
|
/** TELEPEN */
|
||||||
|
TELEPEN,
|
||||||
|
|
||||||
/** UPC-A 1D format. */
|
/** UPC-A 1D format. */
|
||||||
UPC_A,
|
UPC_A,
|
||||||
|
|
||||||
@@ -107,6 +110,7 @@ impl Display for BarcodeFormat {
|
|||||||
BarcodeFormat::MICRO_QR_CODE => "mqr",
|
BarcodeFormat::MICRO_QR_CODE => "mqr",
|
||||||
BarcodeFormat::RSS_14 => "rss 14",
|
BarcodeFormat::RSS_14 => "rss 14",
|
||||||
BarcodeFormat::RSS_EXPANDED => "rss expanded",
|
BarcodeFormat::RSS_EXPANDED => "rss expanded",
|
||||||
|
BarcodeFormat::TELEPEN => "telepen",
|
||||||
BarcodeFormat::UPC_A => "upc a",
|
BarcodeFormat::UPC_A => "upc a",
|
||||||
BarcodeFormat::UPC_E => "upc e",
|
BarcodeFormat::UPC_E => "upc e",
|
||||||
BarcodeFormat::UPC_EAN_EXTENSION => "upc/ean extension",
|
BarcodeFormat::UPC_EAN_EXTENSION => "upc/ean extension",
|
||||||
@@ -149,6 +153,7 @@ impl From<&str> for BarcodeFormat {
|
|||||||
"rss 14" | "rss_14" | "rss14" | "gs1 databar" | "gs1 databar coupon"
|
"rss 14" | "rss_14" | "rss14" | "gs1 databar" | "gs1 databar coupon"
|
||||||
| "gs1_databar_coupon" => BarcodeFormat::RSS_14,
|
| "gs1_databar_coupon" => BarcodeFormat::RSS_14,
|
||||||
"rss expanded" | "expanded rss" | "rss_expanded" => BarcodeFormat::RSS_EXPANDED,
|
"rss expanded" | "expanded rss" | "rss_expanded" => BarcodeFormat::RSS_EXPANDED,
|
||||||
|
"telepen" => BarcodeFormat::TELEPEN,
|
||||||
"upc a" | "upc_a" | "upca" => BarcodeFormat::UPC_A,
|
"upc a" | "upc_a" | "upca" => BarcodeFormat::UPC_A,
|
||||||
"upc e" | "upc_e" | "upce" => BarcodeFormat::UPC_E,
|
"upc e" | "upc_e" | "upce" => BarcodeFormat::UPC_E,
|
||||||
"upc ean extension" | "upc extension" | "ean extension" | "upc/ean extension"
|
"upc ean extension" | "upc extension" | "ean extension" | "upc/ean extension"
|
||||||
|
|||||||
@@ -121,6 +121,12 @@ pub enum DecodeHintType {
|
|||||||
*/
|
*/
|
||||||
#[cfg(feature = "allow_forced_iso_ied_18004_compliance")]
|
#[cfg(feature = "allow_forced_iso_ied_18004_compliance")]
|
||||||
QR_ASSUME_SPEC_CONFORM_INPUT,
|
QR_ASSUME_SPEC_CONFORM_INPUT,
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Will translate the ASCII values parsed by the Telepen reader into the Telepen Numeric form.
|
||||||
|
*/
|
||||||
|
TELEPEN_AS_NUMERIC,
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Data type the hint is expecting.
|
* Data type the hint is expecting.
|
||||||
* Among the possible values the {@link Void} stands out as being used for
|
* Among the possible values the {@link Void} stands out as being used for
|
||||||
@@ -231,4 +237,9 @@ pub enum DecodeHintValue {
|
|||||||
*/
|
*/
|
||||||
#[cfg(feature = "allow_forced_iso_ied_18004_compliance")]
|
#[cfg(feature = "allow_forced_iso_ied_18004_compliance")]
|
||||||
QrAssumeSpecConformInput(bool),
|
QrAssumeSpecConformInput(bool),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Translate the ASCII values parsed by the Telepen reader into the Telepen Numeric form; use {@link Boolean#TRUE}.
|
||||||
|
*/
|
||||||
|
TelepenAsNumeric(bool),
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -180,6 +180,11 @@ pub enum EncodeHintType {
|
|||||||
* exclusive.
|
* exclusive.
|
||||||
*/
|
*/
|
||||||
CODE128_COMPACT,
|
CODE128_COMPACT,
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Will translate the numeric values received by the Telepen writer into the Telepen Alphanumeric form.
|
||||||
|
*/
|
||||||
|
TELEPEN_AS_NUMERIC,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||||
@@ -333,4 +338,9 @@ pub enum EncodeHintValue {
|
|||||||
* exclusive.
|
* exclusive.
|
||||||
*/
|
*/
|
||||||
Code128Compact(bool),
|
Code128Compact(bool),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Translate the numeric values received by the Telepen reader into the Telepen Alphaumeric form; use {@link Boolean#TRUE}.
|
||||||
|
*/
|
||||||
|
TelepenAsNumeric(bool),
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -165,7 +165,8 @@ impl MultiFormatReader {
|
|||||||
|| self.possible_formats.contains(&BarcodeFormat::CODE_128)
|
|| self.possible_formats.contains(&BarcodeFormat::CODE_128)
|
||||||
|| self.possible_formats.contains(&BarcodeFormat::ITF)
|
|| self.possible_formats.contains(&BarcodeFormat::ITF)
|
||||||
|| self.possible_formats.contains(&BarcodeFormat::RSS_14)
|
|| self.possible_formats.contains(&BarcodeFormat::RSS_14)
|
||||||
|| self.possible_formats.contains(&BarcodeFormat::RSS_EXPANDED);
|
|| self.possible_formats.contains(&BarcodeFormat::RSS_EXPANDED)
|
||||||
|
|| self.possible_formats.contains(&BarcodeFormat::TELEPEN);
|
||||||
if one_d && !self.try_harder {
|
if one_d && !self.try_harder {
|
||||||
if let Ok(res) = self.one_d_reader.decode_with_hints(image, &self.hints) {
|
if let Ok(res) = self.one_d_reader.decode_with_hints(image, &self.hints) {
|
||||||
return Ok(res);
|
return Ok(res);
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ use crate::{
|
|||||||
datamatrix::DataMatrixWriter,
|
datamatrix::DataMatrixWriter,
|
||||||
oned::{
|
oned::{
|
||||||
CodaBarWriter, Code128Writer, Code39Writer, Code93Writer, EAN13Writer, EAN8Writer,
|
CodaBarWriter, Code128Writer, Code39Writer, Code93Writer, EAN13Writer, EAN8Writer,
|
||||||
ITFWriter, UPCAWriter, UPCEWriter,
|
ITFWriter, TelepenWriter, UPCAWriter, UPCEWriter,
|
||||||
},
|
},
|
||||||
pdf417::PDF417Writer,
|
pdf417::PDF417Writer,
|
||||||
qrcode::QRCodeWriter,
|
qrcode::QRCodeWriter,
|
||||||
@@ -70,6 +70,7 @@ impl Writer for MultiFormatWriter {
|
|||||||
BarcodeFormat::PDF_417 => Box::<PDF417Writer>::default(),
|
BarcodeFormat::PDF_417 => Box::<PDF417Writer>::default(),
|
||||||
BarcodeFormat::CODABAR => Box::<CodaBarWriter>::default(),
|
BarcodeFormat::CODABAR => Box::<CodaBarWriter>::default(),
|
||||||
BarcodeFormat::DATA_MATRIX => Box::<DataMatrixWriter>::default(),
|
BarcodeFormat::DATA_MATRIX => Box::<DataMatrixWriter>::default(),
|
||||||
|
BarcodeFormat::TELEPEN => Box::<TelepenWriter>::default(),
|
||||||
BarcodeFormat::AZTEC => Box::<AztecWriter>::default(),
|
BarcodeFormat::AZTEC => Box::<AztecWriter>::default(),
|
||||||
_ => {
|
_ => {
|
||||||
return Err(Exceptions::illegal_argument_with(format!(
|
return Err(Exceptions::illegal_argument_with(format!(
|
||||||
|
|||||||
@@ -176,7 +176,8 @@ impl MultiUseMultiFormatReader {
|
|||||||
|| self.possible_formats.contains(&BarcodeFormat::CODE_128)
|
|| self.possible_formats.contains(&BarcodeFormat::CODE_128)
|
||||||
|| self.possible_formats.contains(&BarcodeFormat::ITF)
|
|| self.possible_formats.contains(&BarcodeFormat::ITF)
|
||||||
|| self.possible_formats.contains(&BarcodeFormat::RSS_14)
|
|| self.possible_formats.contains(&BarcodeFormat::RSS_14)
|
||||||
|| self.possible_formats.contains(&BarcodeFormat::RSS_EXPANDED);
|
|| self.possible_formats.contains(&BarcodeFormat::RSS_EXPANDED)
|
||||||
|
|| self.possible_formats.contains(&BarcodeFormat::TELEPEN);
|
||||||
if one_d && !self.try_harder {
|
if one_d && !self.try_harder {
|
||||||
if let Ok(res) = self.one_d_reader.decode_with_hints(image, &self.hints) {
|
if let Ok(res) = self.one_d_reader.decode_with_hints(image, &self.hints) {
|
||||||
return Ok(res);
|
return Ok(res);
|
||||||
|
|||||||
@@ -24,6 +24,9 @@ pub use code_128_reader::*;
|
|||||||
mod itf_reader;
|
mod itf_reader;
|
||||||
pub use itf_reader::*;
|
pub use itf_reader::*;
|
||||||
|
|
||||||
|
mod telepen_reader;
|
||||||
|
pub use telepen_reader::*;
|
||||||
|
|
||||||
mod upc_ean_reader;
|
mod upc_ean_reader;
|
||||||
pub use upc_ean_reader::*;
|
pub use upc_ean_reader::*;
|
||||||
|
|
||||||
@@ -77,6 +80,9 @@ pub use upc_a_writer::*;
|
|||||||
mod ean_13_writer;
|
mod ean_13_writer;
|
||||||
pub use ean_13_writer::*;
|
pub use ean_13_writer::*;
|
||||||
|
|
||||||
|
mod telepen_writer;
|
||||||
|
pub use telepen_writer::*;
|
||||||
|
|
||||||
mod upc_ean_writer;
|
mod upc_ean_writer;
|
||||||
pub use upc_ean_writer::*;
|
pub use upc_ean_writer::*;
|
||||||
|
|
||||||
@@ -85,3 +91,5 @@ pub use ean_8_writer::*;
|
|||||||
|
|
||||||
mod upc_e_writer;
|
mod upc_e_writer;
|
||||||
pub use upc_e_writer::*;
|
pub use upc_e_writer::*;
|
||||||
|
|
||||||
|
mod telepen_common;
|
||||||
@@ -23,6 +23,7 @@ use super::Code93Reader;
|
|||||||
use super::ITFReader;
|
use super::ITFReader;
|
||||||
use super::MultiFormatUPCEANReader;
|
use super::MultiFormatUPCEANReader;
|
||||||
use super::OneDReader;
|
use super::OneDReader;
|
||||||
|
use super::TelepenReader;
|
||||||
use crate::common::Result;
|
use crate::common::Result;
|
||||||
use crate::DecodeHintValue;
|
use crate::DecodeHintValue;
|
||||||
use crate::Exceptions;
|
use crate::Exceptions;
|
||||||
@@ -104,6 +105,11 @@ impl OneDReader for MultiFormatOneDReader {
|
|||||||
return Ok(res);
|
return Ok(res);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if possible_formats.contains(&BarcodeFormat::TELEPEN) {
|
||||||
|
if let Ok(res) = TelepenReader::default().decode_row(row_number, row, hints) {
|
||||||
|
return Ok(res);
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if let Ok(res) =
|
if let Ok(res) =
|
||||||
MultiFormatUPCEANReader::new(internal_hints).decode_row(row_number, row, hints)
|
MultiFormatUPCEANReader::new(internal_hints).decode_row(row_number, row, hints)
|
||||||
@@ -133,6 +139,9 @@ impl OneDReader for MultiFormatOneDReader {
|
|||||||
if let Ok(res) = rss_expanded_reader.decode_row(row_number, row, hints) {
|
if let Ok(res) = rss_expanded_reader.decode_row(row_number, row, hints) {
|
||||||
return Ok(res);
|
return Ok(res);
|
||||||
}
|
}
|
||||||
|
if let Ok(res) = TelepenReader::default().decode_row(row_number, row, hints) {
|
||||||
|
return Ok(res);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Err(Exceptions::NOT_FOUND)
|
Err(Exceptions::NOT_FOUND)
|
||||||
|
|||||||
98
src/oned/telepen_common.rs
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
use crate::Exceptions;
|
||||||
|
use crate::common::Result;
|
||||||
|
|
||||||
|
pub fn calculate_checksum(contents: &str) -> char {
|
||||||
|
let mut sum = 0;
|
||||||
|
|
||||||
|
for c in contents.chars() {
|
||||||
|
sum += c as u32;
|
||||||
|
}
|
||||||
|
|
||||||
|
let remainder = sum % 127;
|
||||||
|
let diff = 127 - remainder;
|
||||||
|
return if diff != 127 {
|
||||||
|
diff as u8 as char
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
0 as char
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn ascii_to_numeric(contents: &str) -> String {
|
||||||
|
let mut number = String::new();
|
||||||
|
|
||||||
|
for c in contents.chars().map(|x| x as u32) {
|
||||||
|
if c >= 27 {
|
||||||
|
number.push_str(&format!("{:0>2}", (c - 27)));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
number.push_str(&format!("{:0>2}", (c - 17)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return number;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn numeric_to_ascii(contents: &str) -> Result<String> {
|
||||||
|
if contents.len() % 2 != 0 {
|
||||||
|
return Err(Exceptions::illegal_argument_with("Input must contain an even number of characters."));
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut ascii = String::new();
|
||||||
|
let mut i = 0;
|
||||||
|
|
||||||
|
while i < contents.len() {
|
||||||
|
let first = contents.chars().nth(i).unwrap() as u8;
|
||||||
|
let second = contents.chars().nth(i + 1).unwrap() as u8;
|
||||||
|
|
||||||
|
if second == 88 && first >= 48 && first <= 57 {
|
||||||
|
ascii.push((17 + first - 48) as char);
|
||||||
|
}
|
||||||
|
else if second >= 48 && second <= 57 && first >= 48 && first <= 57 {
|
||||||
|
ascii.push((27 + (first - 48) * 10 + (second - 48)) as char);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return Err(Exceptions::illegal_argument_with(format!("Input contains an invalid character around position {}.", i.to_string())));
|
||||||
|
}
|
||||||
|
|
||||||
|
i += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Ok(ascii);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn telepen_checksum_test1() {
|
||||||
|
let contents = "Hello world!";
|
||||||
|
let checksum = calculate_checksum(contents);
|
||||||
|
assert_eq!('\u{1a}', checksum);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn telepen_checksum_test2() {
|
||||||
|
let contents = "ABC123456";
|
||||||
|
let checksum = calculate_checksum(contents);
|
||||||
|
assert_eq!('\u{1}', checksum);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn telepen_alpha_to_numeric_test() {
|
||||||
|
let mut ascii = "'=Siu";
|
||||||
|
let mut result = ascii_to_numeric(ascii);
|
||||||
|
assert_eq!("1234567890", result);
|
||||||
|
|
||||||
|
ascii = "& oe";
|
||||||
|
result = ascii_to_numeric(ascii);
|
||||||
|
assert_eq!("11058474", result);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn telepen_numeric_to_ascii_test() {
|
||||||
|
let mut numeric = "1234567890";
|
||||||
|
let mut result = numeric_to_ascii(numeric).unwrap();
|
||||||
|
assert_eq!("'=Siu", result);
|
||||||
|
|
||||||
|
numeric = "11058474";
|
||||||
|
result = numeric_to_ascii(numeric).unwrap();
|
||||||
|
assert_eq!("& oe", result);
|
||||||
|
}
|
||||||
436
src/oned/telepen_reader.rs
Normal file
@@ -0,0 +1,436 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
use rxing_one_d_proc_derive::OneDReader;
|
||||||
|
|
||||||
|
use crate::common::{BitArray, Result};
|
||||||
|
use crate::Exceptions;
|
||||||
|
use crate::RXingResult;
|
||||||
|
use crate::DecodeHintValue;
|
||||||
|
use crate::oned::telepen_common;
|
||||||
|
use crate::{point_f, BarcodeFormat};
|
||||||
|
use bit_reverse::ParallelReverse;
|
||||||
|
|
||||||
|
use super::OneDReader;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Decodes Telepen barcodes.</p>
|
||||||
|
*
|
||||||
|
* @author Chris Wood
|
||||||
|
*/
|
||||||
|
#[derive(OneDReader)]
|
||||||
|
pub struct TelepenReader {
|
||||||
|
// Keep some instance variables to avoid reallocations
|
||||||
|
counters: Vec<u32>,
|
||||||
|
counterLength: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for TelepenReader {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
counters: vec![0; 80],
|
||||||
|
counterLength: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl OneDReader for TelepenReader {
|
||||||
|
fn decode_row(
|
||||||
|
&mut self,
|
||||||
|
rowNumber: u32,
|
||||||
|
row: &crate::common::BitArray,
|
||||||
|
hints: &crate::DecodingHintDictionary,
|
||||||
|
) -> Result<crate::RXingResult> {
|
||||||
|
self.counters.fill(0);
|
||||||
|
self.setCounters(row, (row.get_size() as f32 * 0.001) as u32)?;
|
||||||
|
|
||||||
|
let startOffset = self.findStartPattern()? as usize;
|
||||||
|
let end = self.findEndPattern(startOffset)? as usize;
|
||||||
|
|
||||||
|
let theCounters = &self.counters;
|
||||||
|
let mut maxBar = 0;
|
||||||
|
let mut minBar = u32::MAX;
|
||||||
|
|
||||||
|
// 0 position value will be whitespace prior to the barcode beginning
|
||||||
|
let mut j = startOffset;
|
||||||
|
|
||||||
|
// Calculate a median bar / gap width by establishing the smallest and
|
||||||
|
// largest gaps.
|
||||||
|
while j <= end {
|
||||||
|
let currentCounter = theCounters[j];
|
||||||
|
if currentCounter < minBar {
|
||||||
|
minBar = currentCounter;
|
||||||
|
}
|
||||||
|
if currentCounter > maxBar {
|
||||||
|
maxBar = currentCounter;
|
||||||
|
}
|
||||||
|
|
||||||
|
j += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate median value as float.
|
||||||
|
let mut thresholdBar = (minBar + maxBar) as f64 / 2.0;
|
||||||
|
|
||||||
|
// Lean very slightly toward thicker bars.
|
||||||
|
thresholdBar = thresholdBar - (thresholdBar / 10.0);
|
||||||
|
|
||||||
|
// Start of the barcode is always a black bar.
|
||||||
|
let mut isBlack = true;
|
||||||
|
|
||||||
|
let mut pattern: Vec<u32> = vec![0; self.counterLength];
|
||||||
|
let mut patternLength: usize = 0;
|
||||||
|
|
||||||
|
pattern.fill(0);
|
||||||
|
|
||||||
|
j = startOffset;
|
||||||
|
|
||||||
|
// Categorise each value into narrow or wide black or white. Each
|
||||||
|
// permutation is signified by an integer value.
|
||||||
|
//
|
||||||
|
// 0 = Narrow White
|
||||||
|
// 1 = Narrow Black
|
||||||
|
// 2 = Wide White
|
||||||
|
// 3 = Wide Black
|
||||||
|
//
|
||||||
|
// Wide elements are 3x the width of narrow, thus:
|
||||||
|
//
|
||||||
|
// Black narrow: B
|
||||||
|
// Black wide: BBB
|
||||||
|
// White narrow: .
|
||||||
|
// White wide: ...
|
||||||
|
|
||||||
|
while j <= end {
|
||||||
|
let currentCounter = theCounters[j];
|
||||||
|
if (currentCounter as f64) < thresholdBar {
|
||||||
|
if isBlack {
|
||||||
|
// Narrow black: B
|
||||||
|
pattern[patternLength] = 1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Narrow white: .
|
||||||
|
pattern[patternLength] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if isBlack {
|
||||||
|
// Wide black: BBB
|
||||||
|
pattern[patternLength] = 3;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Wide white: ...
|
||||||
|
pattern[patternLength] = 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
patternLength += 1;
|
||||||
|
j += 1;
|
||||||
|
isBlack = !isBlack;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut bits: BitArray = BitArray::new();
|
||||||
|
let mut state = 0;
|
||||||
|
j = 0;
|
||||||
|
|
||||||
|
// Convert narrow-wide sequence into bit array.
|
||||||
|
while j < patternLength - 1 {
|
||||||
|
|
||||||
|
if pattern[j] == 3 && pattern[j + 1] == 2 {
|
||||||
|
// BBB... = 010
|
||||||
|
bits.appendBit(false);
|
||||||
|
bits.appendBit(true);
|
||||||
|
bits.appendBit(false);
|
||||||
|
}
|
||||||
|
else if pattern[j] == 3 && pattern[j + 1] == 0 {
|
||||||
|
// BBB. = 00
|
||||||
|
bits.appendBit(false);
|
||||||
|
bits.appendBit(false);
|
||||||
|
}
|
||||||
|
else if pattern[j] == 1 && pattern[j + 1] == 2 && state == 0 {
|
||||||
|
// B... = 01
|
||||||
|
bits.appendBit(false);
|
||||||
|
bits.appendBit(true);
|
||||||
|
state = 1;
|
||||||
|
}
|
||||||
|
else if pattern[j] == 1 && pattern[j + 1] == 2 && state == 1 {
|
||||||
|
// B... = 10
|
||||||
|
bits.appendBit(true);
|
||||||
|
bits.appendBit(false);
|
||||||
|
state = 0;
|
||||||
|
}
|
||||||
|
else if pattern[j] == 1 && pattern[j + 1] == 0 {
|
||||||
|
// B. = 1
|
||||||
|
bits.appendBit(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
j += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
let byteLength = bits.getSizeInBytes();
|
||||||
|
|
||||||
|
// Any Telepen barcode will be longer than two bytes.
|
||||||
|
if byteLength < 3 {
|
||||||
|
return Err(Exceptions::NOT_FOUND);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut bytes: Vec<u8> = vec![0; byteLength];
|
||||||
|
bits.toBytes(0, bytes.as_mut_slice(), 0, byteLength);
|
||||||
|
|
||||||
|
j = 0;
|
||||||
|
|
||||||
|
// Tweak our byte array to clean things up a little.
|
||||||
|
while j < byteLength {
|
||||||
|
// Telepen is little-endian, so need to swap the
|
||||||
|
// bits around for each byte to be correct.
|
||||||
|
bytes[j] = bytes[j].swap_bits();
|
||||||
|
|
||||||
|
// The first bit in the byte can always be disregarded
|
||||||
|
// as the highest ASCII decimal value is 127. It might be
|
||||||
|
// set because it is used as a parity bit during encoding
|
||||||
|
// (ensuring that there is an equal number of 1 bits in the
|
||||||
|
// byte).
|
||||||
|
if bytes[j] >= 128 {
|
||||||
|
bytes[j] -= 128;
|
||||||
|
}
|
||||||
|
|
||||||
|
j += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// First character should be _ which is decimal 95.
|
||||||
|
if bytes[0] != 95 {
|
||||||
|
return Err(Exceptions::NOT_FOUND);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Last character should be z which is decimal 122.
|
||||||
|
if bytes[byteLength - 1] != 122 {
|
||||||
|
return Err(Exceptions::NOT_FOUND);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Content bytes
|
||||||
|
let contentBytes = bytes[1 .. byteLength - 2].to_vec();
|
||||||
|
let mut contentString = String::from_utf8_lossy(&contentBytes).to_string();
|
||||||
|
|
||||||
|
// Penultimate byte is a block check character.
|
||||||
|
let check = bytes[byteLength - 2];
|
||||||
|
|
||||||
|
let checksum = telepen_common::calculate_checksum(&contentString);
|
||||||
|
|
||||||
|
// Validate checksum
|
||||||
|
if check != checksum as u8 {
|
||||||
|
return Err(Exceptions::NOT_FOUND);
|
||||||
|
}
|
||||||
|
|
||||||
|
if matches!(
|
||||||
|
hints.get(&DecodeHintType::TELEPEN_AS_NUMERIC),
|
||||||
|
Some(DecodeHintValue::TelepenAsNumeric(true))
|
||||||
|
) {
|
||||||
|
contentString = telepen_common::ascii_to_numeric(&contentString);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut runningCount = 0;
|
||||||
|
runningCount += self.counters.iter().take(startOffset).sum::<u32>();
|
||||||
|
let left: f32 = runningCount as f32;
|
||||||
|
|
||||||
|
runningCount += self
|
||||||
|
.counters
|
||||||
|
.iter()
|
||||||
|
.skip(startOffset)
|
||||||
|
.take(self.counterLength - startOffset - end)
|
||||||
|
.sum::<u32>();
|
||||||
|
|
||||||
|
let right: f32 = runningCount as f32;
|
||||||
|
|
||||||
|
let mut result = RXingResult::new(
|
||||||
|
&contentString,
|
||||||
|
bytes,
|
||||||
|
vec![
|
||||||
|
point_f(left, rowNumber as f32),
|
||||||
|
point_f(right, rowNumber as f32),
|
||||||
|
],
|
||||||
|
BarcodeFormat::TELEPEN,
|
||||||
|
);
|
||||||
|
|
||||||
|
result.putMetadata(
|
||||||
|
RXingResultMetadataType::SYMBOLOGY_IDENTIFIER,
|
||||||
|
RXingResultMetadataValue::SymbologyIdentifier("]B0".to_owned()),
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl TelepenReader {
|
||||||
|
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
counters: vec![0; 80], //Vec::with_capacity(80),
|
||||||
|
counterLength: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Records the size of all runs of white and black pixels, starting with white.
|
||||||
|
* This is just like recordPattern, except it records all the counters, and
|
||||||
|
* uses our builtin "counters" member for storage.
|
||||||
|
* @param row row to count from
|
||||||
|
*/
|
||||||
|
fn setCounters(&mut self, row: &BitArray, minToleratedWidth: u32) -> Result<()> {
|
||||||
|
self.counterLength = 0;
|
||||||
|
|
||||||
|
let mut i = 1;
|
||||||
|
let end = row.get_size();
|
||||||
|
let mut currentColor = false;
|
||||||
|
let mut count = 1;
|
||||||
|
|
||||||
|
// Move to first white pixel
|
||||||
|
while i < end && row.get(i) {
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
while i < end {
|
||||||
|
if row.get(i) == currentColor {
|
||||||
|
count += 1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if count >= minToleratedWidth || self.counterLength == 0 {
|
||||||
|
self.counterAppend(count);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Noise from previous bar. Treat it as the
|
||||||
|
// previous colour.
|
||||||
|
self.counters[self.counterLength - 1] += count;
|
||||||
|
}
|
||||||
|
|
||||||
|
count = 1;
|
||||||
|
currentColor = !currentColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if count >= minToleratedWidth {
|
||||||
|
self.counterAppend(count);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Noise from previous bar. Treat it as the
|
||||||
|
// previous colour.
|
||||||
|
self.counters[self.counterLength - 1] += count;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn counterAppend(&mut self, e: u32) {
|
||||||
|
self.counters[self.counterLength] = e;
|
||||||
|
self.counterLength += 1;
|
||||||
|
if self.counterLength >= self.counters.len() {
|
||||||
|
let mut temp = vec![0; self.counterLength * 2];
|
||||||
|
temp[0..self.counterLength].clone_from_slice(&self.counters[..]);
|
||||||
|
self.counters = temp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn findStartPattern(&mut self) -> Result<u32> {
|
||||||
|
if self.counterLength <= 20 {
|
||||||
|
return Err(Exceptions::NOT_FOUND);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut i = 0;
|
||||||
|
while i < self.counterLength - 20 {
|
||||||
|
// Read next 20 in sequence. All 20 must be either between 28% and 38%
|
||||||
|
// of biggest, or between 90% to 100% of biggest.
|
||||||
|
let mut j = 0;
|
||||||
|
let mut maxBar: f32 = 0.0;
|
||||||
|
let mut minBar: f32 = f32::MAX;
|
||||||
|
|
||||||
|
while i + j < self.counterLength && j < 20 {
|
||||||
|
if (self.counters[i + j] as f32) > maxBar {
|
||||||
|
maxBar = self.counters[i + j] as f32;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (self.counters[ i + j] as f32) < minBar {
|
||||||
|
minBar = self.counters[ i + j] as f32;
|
||||||
|
}
|
||||||
|
|
||||||
|
j += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
j = 0;
|
||||||
|
|
||||||
|
let median = minBar as f32 + maxBar as f32 / 2.0;
|
||||||
|
let mut passed = true;
|
||||||
|
|
||||||
|
// First 10 items must be:
|
||||||
|
// N-N-N-N-N-N-N-N-N-N-W
|
||||||
|
while i + j < self.counterLength && j < 11 {
|
||||||
|
if j < 10 {
|
||||||
|
// Narrow
|
||||||
|
if (self.counters[i + j] as f32) > median {
|
||||||
|
passed = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if j == 10 {
|
||||||
|
// Wide
|
||||||
|
if (self.counters[i + j] as f32) < median {
|
||||||
|
passed = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
j += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if !passed {
|
||||||
|
i += 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Ok(i as u32);
|
||||||
|
}
|
||||||
|
Err(Exceptions::NOT_FOUND)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn findEndPattern(&mut self, start: usize) -> Result<u32> {
|
||||||
|
const TOLERANCE: f32 = 0.5;
|
||||||
|
|
||||||
|
let mut i = start;
|
||||||
|
while i < self.counterLength {
|
||||||
|
// Read next 20 in sequence. All 20 must be either between 28% and 38%
|
||||||
|
// of biggest, or between 90% to 100% of biggest.
|
||||||
|
let mut j = 0;
|
||||||
|
let mut maxBar: f32 = 0.0;
|
||||||
|
|
||||||
|
while i + j < self.counterLength && j < 20 {
|
||||||
|
if (self.counters[i + j] as f32) > maxBar {
|
||||||
|
maxBar = self.counters[i + j] as f32;
|
||||||
|
}
|
||||||
|
|
||||||
|
j += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
i = start + 20;
|
||||||
|
|
||||||
|
while i < self.counterLength {
|
||||||
|
if (self.counters[i] as f32) > (maxBar as f32 * (1.0 + TOLERANCE)) {
|
||||||
|
return Ok((i - 1) as u32);
|
||||||
|
}
|
||||||
|
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Ok((self.counterLength - 1) as u32);
|
||||||
|
}
|
||||||
|
}
|
||||||
276
src/oned/telepen_writer.rs
Normal file
@@ -0,0 +1,276 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2011 ZXing authors
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
use rxing_one_d_proc_derive::OneDWriter;
|
||||||
|
use regex::Regex;
|
||||||
|
use crate::common::Result;
|
||||||
|
use crate::BarcodeFormat;
|
||||||
|
use crate::oned::telepen_common;
|
||||||
|
|
||||||
|
use super::OneDimensionalCodeWriter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class renders Telepen as {@code boolean[]}.
|
||||||
|
*
|
||||||
|
* @author Chris Wood
|
||||||
|
*/
|
||||||
|
#[derive(OneDWriter, Default)]
|
||||||
|
pub struct TelepenWriter;
|
||||||
|
|
||||||
|
impl OneDimensionalCodeWriter for TelepenWriter {
|
||||||
|
fn encode_oned(&self, contents: &str) -> Result<Vec<bool>> {
|
||||||
|
self.encode_oned_with_hints(contents, &HashMap::new())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn encode_oned_with_hints(&self, contents: &str,
|
||||||
|
hints: &crate::EncodingHintDictionary) -> Result<Vec<bool>> {
|
||||||
|
|
||||||
|
let mut decodedContents = contents.to_string();
|
||||||
|
|
||||||
|
if matches!(
|
||||||
|
hints.get(&EncodeHintType::TELEPEN_AS_NUMERIC),
|
||||||
|
Some(EncodeHintValue::TelepenAsNumeric(true))
|
||||||
|
) {
|
||||||
|
decodedContents = telepen_common::numeric_to_ascii(&contents)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate the checksum character
|
||||||
|
let checksum = telepen_common::calculate_checksum(&decodedContents);
|
||||||
|
|
||||||
|
// Build binary string
|
||||||
|
let mut binary = String::new();
|
||||||
|
|
||||||
|
// Opening character is always _
|
||||||
|
binary = self.add_to_binary('_', binary);
|
||||||
|
|
||||||
|
// Content
|
||||||
|
for c in decodedContents.chars() {
|
||||||
|
if c as u32 > 127 {
|
||||||
|
return Err(Exceptions::illegal_argument_with(format!(
|
||||||
|
"Telepen only supports ASCII characters."
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
|
||||||
|
binary = self.add_to_binary(c, binary)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Checksum
|
||||||
|
binary = self.add_to_binary(checksum, binary);
|
||||||
|
|
||||||
|
// Closing character is always z.
|
||||||
|
binary = self.add_to_binary('z', binary);
|
||||||
|
|
||||||
|
let re = Regex::new(r"^01|10$|01*0|00|1").unwrap();
|
||||||
|
let matches: Vec<&str> = re.find_iter(&binary).map(|m| m.as_str()).collect();
|
||||||
|
|
||||||
|
let mut result = vec![false; 2000];
|
||||||
|
let mut resultPosition = 0;
|
||||||
|
|
||||||
|
for b in matches {
|
||||||
|
match b {
|
||||||
|
"010" => {
|
||||||
|
// BBB...
|
||||||
|
result[resultPosition] = true;
|
||||||
|
result[resultPosition + 1] = true;
|
||||||
|
result[resultPosition + 2] = true;
|
||||||
|
result[resultPosition + 3] = false;
|
||||||
|
result[resultPosition + 4] = false;
|
||||||
|
result[resultPosition + 5] = false;
|
||||||
|
|
||||||
|
resultPosition += 6;
|
||||||
|
},
|
||||||
|
"00" => {
|
||||||
|
// BBB.
|
||||||
|
result[resultPosition] = true;
|
||||||
|
result[resultPosition + 1] = true;
|
||||||
|
result[resultPosition + 2] = true;
|
||||||
|
result[resultPosition + 3] = false;
|
||||||
|
|
||||||
|
resultPosition += 4;
|
||||||
|
},
|
||||||
|
"1" => {
|
||||||
|
// B.
|
||||||
|
result[resultPosition] = true;
|
||||||
|
result[resultPosition + 1] = false;
|
||||||
|
|
||||||
|
resultPosition += 2;
|
||||||
|
},
|
||||||
|
"01" => {
|
||||||
|
// B...
|
||||||
|
result[resultPosition] = true;
|
||||||
|
result[resultPosition + 1] = false;
|
||||||
|
result[resultPosition + 2] = false;
|
||||||
|
result[resultPosition + 3] = false;
|
||||||
|
|
||||||
|
resultPosition += 4;
|
||||||
|
},
|
||||||
|
"10" => {
|
||||||
|
// B...
|
||||||
|
result[resultPosition] = true;
|
||||||
|
result[resultPosition + 1] = false;
|
||||||
|
result[resultPosition + 2] = false;
|
||||||
|
result[resultPosition + 3] = false;
|
||||||
|
|
||||||
|
resultPosition += 4;
|
||||||
|
},
|
||||||
|
"0" => {
|
||||||
|
return Err(Exceptions::illegal_argument_with(format!(
|
||||||
|
"Invalid bit combination!"
|
||||||
|
)));
|
||||||
|
},
|
||||||
|
_ => {
|
||||||
|
// B... (B.)* B...
|
||||||
|
result[resultPosition] = true;
|
||||||
|
result[resultPosition + 1] = false;
|
||||||
|
result[resultPosition + 2] = false;
|
||||||
|
result[resultPosition + 3] = false;
|
||||||
|
|
||||||
|
resultPosition += 4;
|
||||||
|
|
||||||
|
for _j in 2 .. b.len() - 2 {
|
||||||
|
result[resultPosition] = true;
|
||||||
|
result[resultPosition + 1] = false;
|
||||||
|
|
||||||
|
resultPosition += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
result[resultPosition] = true;
|
||||||
|
result[resultPosition + 1] = false;
|
||||||
|
result[resultPosition + 2] = false;
|
||||||
|
result[resultPosition + 3] = false;
|
||||||
|
|
||||||
|
resultPosition += 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(result[0 .. resultPosition - 1].to_vec())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn getSupportedWriteFormats(&self) -> Option<Vec<crate::BarcodeFormat>> {
|
||||||
|
Some(vec![BarcodeFormat::TELEPEN])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TelepenWriter {
|
||||||
|
fn get_bits(&self, byte: u8) -> Vec<bool> {
|
||||||
|
let mut bits = vec![false; 8];
|
||||||
|
let mut oneCount = 0;
|
||||||
|
|
||||||
|
for i in 0..8 {
|
||||||
|
let mask = 1 << i;
|
||||||
|
bits[i] = (mask & byte) > 0;
|
||||||
|
|
||||||
|
if bits[i] {
|
||||||
|
oneCount += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set parity bit - there must be an even number
|
||||||
|
// of 1s in the 8 bits.
|
||||||
|
bits[7] = oneCount % 2 != 0;
|
||||||
|
|
||||||
|
return bits;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_to_binary(&self, c: char, mut binary: String) -> String {
|
||||||
|
let byte = c as u8;
|
||||||
|
let bits = self.get_bits(byte);
|
||||||
|
|
||||||
|
for i in 0..8 {
|
||||||
|
binary.push(if bits[i] {
|
||||||
|
'1'
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
'0'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return binary;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Chris Wood
|
||||||
|
*/
|
||||||
|
#[cfg(test)]
|
||||||
|
mod TelepenWriterTestCase {
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
common::{bit_matrix_test_case, BitMatrix},
|
||||||
|
BarcodeFormat, Writer, EncodeHintType, EncodeHintValue,
|
||||||
|
};
|
||||||
|
|
||||||
|
use super::TelepenWriter;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[should_panic]
|
||||||
|
fn testAsciiOnly() {
|
||||||
|
encode("АБВГДЕЁЖ");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn testEncode() {
|
||||||
|
doTest(
|
||||||
|
"Hello world!",
|
||||||
|
concat!(
|
||||||
|
"00000",
|
||||||
|
"10101010101110001110111000111000101110001000100011101010100010001110101010001000101010101000100011101110111000101010101000101000101010101000100011100010001010001110101010001000111010111010101010111011101011101110001010111010111000101010101",
|
||||||
|
"00000",
|
||||||
|
),
|
||||||
|
false
|
||||||
|
);
|
||||||
|
|
||||||
|
doTest(
|
||||||
|
"11058474",
|
||||||
|
concat!(
|
||||||
|
"00000",
|
||||||
|
"101010101011100010001000111000101110111011100010101010101000100010111000100010001010111010001000111000101010101",
|
||||||
|
"00000",
|
||||||
|
),
|
||||||
|
true
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn doTest(input: &str, expected: &str, numeric: bool) {
|
||||||
|
let result: BitMatrix;
|
||||||
|
|
||||||
|
if numeric {
|
||||||
|
result = encode_with_hints(input);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
result = encode(input);
|
||||||
|
};
|
||||||
|
|
||||||
|
assert_eq!(expected, bit_matrix_test_case::matrix_to_string(&result));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn encode(input: &str) -> BitMatrix {
|
||||||
|
TelepenWriter
|
||||||
|
.encode(input, &BarcodeFormat::TELEPEN, 0, 0)
|
||||||
|
.expect("must encode")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn encode_with_hints(input: &str) -> BitMatrix {
|
||||||
|
let mut hints = HashMap::new();
|
||||||
|
hints.insert(EncodeHintType::TELEPEN_AS_NUMERIC, EncodeHintValue::TelepenAsNumeric(true));
|
||||||
|
|
||||||
|
TelepenWriter
|
||||||
|
.encode_with_hints(input, &BarcodeFormat::TELEPEN, 0, 0, &hints)
|
||||||
|
.expect("must encode")
|
||||||
|
}
|
||||||
|
}
|
||||||
1
test_resources/blackbox/telepen-1/01.metadata.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
SYMBOLOGY_IDENTIFIER=]B0
|
||||||
BIN
test_resources/blackbox/telepen-1/01.png
Normal file
|
After Width: | Height: | Size: 3.3 KiB |
1
test_resources/blackbox/telepen-1/01.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
Test
|
||||||
BIN
test_resources/blackbox/telepen-1/02.png
Normal file
|
After Width: | Height: | Size: 2.6 KiB |
1
test_resources/blackbox/telepen-1/02.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
Wikipedia
|
||||||
BIN
test_resources/blackbox/telepen-1/03.png
Normal file
|
After Width: | Height: | Size: 2.1 KiB |
1
test_resources/blackbox/telepen-1/03.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
Hello world!
|
||||||
BIN
test_resources/blackbox/telepen-1/04.png
Normal file
|
After Width: | Height: | Size: 13 MiB |
1
test_resources/blackbox/telepen-1/04.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
Hello world!
|
||||||
BIN
test_resources/blackbox/telepen-1/05.png
Normal file
|
After Width: | Height: | Size: 12 MiB |
1
test_resources/blackbox/telepen-1/05.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
Hello world!
|
||||||
BIN
test_resources/blackbox/telepen-2/01.png
Normal file
|
After Width: | Height: | Size: 9.9 KiB |
1
test_resources/blackbox/telepen-2/01.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
1234567890
|
||||||
BIN
test_resources/blackbox/telepen-2/02.png
Normal file
|
After Width: | Height: | Size: 12 MiB |
1
test_resources/blackbox/telepen-2/02.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
11058474
|
||||||
BIN
test_resources/blackbox/telepen-2/03.png
Normal file
|
After Width: | Height: | Size: 14 MiB |
1
test_resources/blackbox/telepen-2/03.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
10398404
|
||||||
BIN
test_resources/blackbox/telepen-2/04.png
Normal file
|
After Width: | Height: | Size: 12 MiB |
1
test_resources/blackbox/telepen-2/04.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
10483931
|
||||||
BIN
test_resources/blackbox/telepen-2/05.png
Normal file
|
After Width: | Height: | Size: 11 MiB |
1
test_resources/blackbox/telepen-2/05.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
11193263
|
||||||
BIN
test_resources/blackbox/telepen-2/06.png
Normal file
|
After Width: | Height: | Size: 13 MiB |
1
test_resources/blackbox/telepen-2/06.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
11264314
|
||||||
BIN
test_resources/blackbox/telepen-2/07.png
Normal file
|
After Width: | Height: | Size: 11 MiB |
1
test_resources/blackbox/telepen-2/07.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
11188986
|
||||||
53
tests/telepen_blackbox_1_test_case.rs
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
use rxing::{oned::TelepenReader, BarcodeFormat};
|
||||||
|
|
||||||
|
mod common;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Chris Wood
|
||||||
|
*/
|
||||||
|
#[test]
|
||||||
|
fn telepen_alpha_test_case() {
|
||||||
|
const NUMTESTS: u32 = 5;
|
||||||
|
|
||||||
|
let mut tester = common::AbstractBlackBoxTestCase::new(
|
||||||
|
"test_resources/blackbox/telepen-1",
|
||||||
|
TelepenReader::new(),
|
||||||
|
BarcodeFormat::TELEPEN,
|
||||||
|
);
|
||||||
|
// super("src/test/resources/blackbox/Telepen-1", new MultiFormatReader(), BarcodeFormat.Telepen);
|
||||||
|
tester.add_test(NUMTESTS, 2, 0.0);
|
||||||
|
tester.add_test(NUMTESTS, 2, 180.0);
|
||||||
|
|
||||||
|
tester.test_black_box();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn telepen_numeric_test_case() {
|
||||||
|
let mut tester = common::AbstractBlackBoxTestCase::new(
|
||||||
|
"test_resources/blackbox/telepen-2",
|
||||||
|
TelepenReader::new(),
|
||||||
|
BarcodeFormat::TELEPEN,
|
||||||
|
);
|
||||||
|
|
||||||
|
tester.add_test_complex(7, 1, 0, 0, 0.0);
|
||||||
|
tester.add_hint(rxing::DecodeHintType::TELEPEN_AS_NUMERIC, rxing::DecodeHintValue::TelepenAsNumeric(true));
|
||||||
|
tester.ignore_pure = true;
|
||||||
|
|
||||||
|
tester.test_black_box();
|
||||||
|
}
|
||||||