mirror of
https://github.com/starovoid/rxing.git
synced 2026-07-26 04:12:34 +00:00
Merge pull request #20 from SteveCookTU/generics
BREAKING CHANGE: Transition from dynamic dispatch to generics This changes the fundamental interface into this library. Users who are not using the helper methods will need to refactor their code. This is now targeted at the 0.4.0 release.
This commit is contained in:
12
Cargo.toml
12
Cargo.toml
@@ -36,6 +36,7 @@ thiserror = "1.0.38"
|
||||
java-properties = "1.4.1"
|
||||
java-rand = "0.2.0"
|
||||
rand = "0.8.5"
|
||||
criterion = "0.4.0"
|
||||
|
||||
[features]
|
||||
default = ["image"]
|
||||
@@ -68,4 +69,13 @@ otsu_level = ["image"]
|
||||
members = [
|
||||
"crates/one-d-proc-derive",
|
||||
"crates/cli"
|
||||
]
|
||||
]
|
||||
|
||||
[[bench]]
|
||||
name = "benchmarks"
|
||||
harness = false
|
||||
|
||||
[profile.release]
|
||||
codegen-units = 1
|
||||
lto = true
|
||||
opt-level = 3
|
||||
204
benches/benchmarks.rs
Normal file
204
benches/benchmarks.rs
Normal file
@@ -0,0 +1,204 @@
|
||||
use criterion::{criterion_group, criterion_main, Criterion};
|
||||
use rxing::aztec::AztecReader;
|
||||
use rxing::common::HybridBinarizer;
|
||||
use rxing::datamatrix::DataMatrixReader;
|
||||
use rxing::maxicode::MaxiCodeReader;
|
||||
use rxing::oned::rss::expanded::RSSExpandedReader;
|
||||
use rxing::oned::rss::RSS14Reader;
|
||||
use rxing::oned::{
|
||||
CodaBarReader, Code39Reader, Code93Reader, EAN13Reader, EAN8Reader, ITFReader, UPCAReader,
|
||||
UPCEReader,
|
||||
};
|
||||
use rxing::pdf417::PDF417Reader;
|
||||
use rxing::qrcode::QRCodeReader;
|
||||
use rxing::{BinaryBitmap, BufferedImageLuminanceSource, Reader};
|
||||
use std::path::Path;
|
||||
|
||||
fn get_image(
|
||||
path: impl AsRef<Path>,
|
||||
) -> BinaryBitmap<HybridBinarizer<BufferedImageLuminanceSource>> {
|
||||
BinaryBitmap::new(HybridBinarizer::new(BufferedImageLuminanceSource::new(
|
||||
image::open(path).unwrap(),
|
||||
)))
|
||||
}
|
||||
|
||||
fn aztec_benchmark(c: &mut Criterion) {
|
||||
let mut image = get_image("test_resources/blackbox/aztec-1/abc-37x37.png");
|
||||
let mut reader = AztecReader::default();
|
||||
|
||||
c.bench_function("aztec", |b| {
|
||||
b.iter(|| {
|
||||
let _res = reader.decode(&mut image);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
fn codabar_benchmark(c: &mut Criterion) {
|
||||
let mut image = get_image("test_resources/blackbox/codabar-1/02.png");
|
||||
let mut reader = CodaBarReader::default();
|
||||
|
||||
c.bench_function("codabar", |b| {
|
||||
b.iter(|| {
|
||||
let _res = reader.decode(&mut image);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
fn code39_benchmark(c: &mut Criterion) {
|
||||
let mut image = get_image("test_resources/blackbox/code39-1/1.png");
|
||||
let mut reader = Code39Reader::default();
|
||||
|
||||
c.bench_function("code39", |b| {
|
||||
b.iter(|| {
|
||||
let _res = reader.decode(&mut image);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
fn code93_benchmark(c: &mut Criterion) {
|
||||
let mut image = get_image("test_resources/blackbox/code93-1/1.png");
|
||||
let mut reader = Code93Reader::default();
|
||||
|
||||
c.bench_function("code93", |b| {
|
||||
b.iter(|| {
|
||||
let _res = reader.decode(&mut image);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
fn datamatrix_benchmark(c: &mut Criterion) {
|
||||
let mut image = get_image("test_resources/blackbox/datamatrix-1/C40.png");
|
||||
let mut reader = DataMatrixReader::default();
|
||||
|
||||
c.bench_function("datamatrix", |b| {
|
||||
b.iter(|| {
|
||||
let _res = reader.decode(&mut image);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
fn ean8_benchmark(c: &mut Criterion) {
|
||||
let mut image = get_image("test_resources/blackbox/ean8-1/1.png");
|
||||
let mut reader = EAN8Reader::default();
|
||||
|
||||
c.bench_function("ean8", |b| {
|
||||
b.iter(|| {
|
||||
let _res = reader.decode(&mut image);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
fn ean13_benchmark(c: &mut Criterion) {
|
||||
let mut image = get_image("test_resources/blackbox/ean13-1/1.png");
|
||||
let mut reader = EAN13Reader::default();
|
||||
|
||||
c.bench_function("ean13", |b| {
|
||||
b.iter(|| {
|
||||
let _res = reader.decode(&mut image);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
fn itf_benchmark(c: &mut Criterion) {
|
||||
let mut image = get_image("test_resources/blackbox/itf-1/1.png");
|
||||
let mut reader = ITFReader::default();
|
||||
|
||||
c.bench_function("itf", |b| {
|
||||
b.iter(|| {
|
||||
let _res = reader.decode(&mut image);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
fn maxicode_benchmark(c: &mut Criterion) {
|
||||
let mut image = get_image("test_resources/blackbox/maxicode-1/1.png");
|
||||
let mut reader = MaxiCodeReader::default();
|
||||
|
||||
c.bench_function("maxicode", |b| {
|
||||
b.iter(|| {
|
||||
let _res = reader.decode(&mut image);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
fn pdf417_benchmark(c: &mut Criterion) {
|
||||
let mut image = get_image("test_resources/blackbox/pdf417-1/01.png");
|
||||
let mut reader = PDF417Reader::default();
|
||||
|
||||
c.bench_function("pdf417", |b| {
|
||||
b.iter(|| {
|
||||
let _res = reader.decode(&mut image);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
fn qrcode_benchmark(c: &mut Criterion) {
|
||||
let mut image = get_image("test_resources/blackbox/qrcode-2/1.png");
|
||||
let mut reader = QRCodeReader::default();
|
||||
|
||||
c.bench_function("qrcode", |b| {
|
||||
b.iter(|| {
|
||||
let _res = reader.decode(&mut image);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
fn rss14_benchmark(c: &mut Criterion) {
|
||||
let mut image = get_image("test_resources/blackbox/rss14-1/3.png");
|
||||
c.bench_function("rss14", |b| {
|
||||
b.iter(|| {
|
||||
let mut reader = RSS14Reader::default();
|
||||
let _res = reader.decode(&mut image);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
fn rss_expanded_benchmark(c: &mut Criterion) {
|
||||
let mut image = get_image("test_resources/blackbox/rssexpanded-1/1.png");
|
||||
c.bench_function("rss_expanded", |b| {
|
||||
b.iter(|| {
|
||||
let mut reader = RSSExpandedReader::default();
|
||||
let _res = reader.decode(&mut image);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
fn upca_benchmark(c: &mut Criterion) {
|
||||
let mut image = get_image("test_resources/blackbox/upca-4/1.png");
|
||||
c.bench_function("upca", |b| {
|
||||
b.iter(|| {
|
||||
let mut reader = UPCAReader::default();
|
||||
let _res = reader.decode(&mut image);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
fn upce_benchmark(c: &mut Criterion) {
|
||||
let mut image = get_image("test_resources/blackbox/upce-1/1.png");
|
||||
c.bench_function("upce", |b| {
|
||||
b.iter(|| {
|
||||
let mut reader = UPCEReader::default();
|
||||
let _res = reader.decode(&mut image);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
criterion_group!(
|
||||
benches,
|
||||
aztec_benchmark,
|
||||
codabar_benchmark,
|
||||
code39_benchmark,
|
||||
code93_benchmark,
|
||||
datamatrix_benchmark,
|
||||
ean8_benchmark,
|
||||
ean13_benchmark,
|
||||
itf_benchmark,
|
||||
maxicode_benchmark,
|
||||
pdf417_benchmark,
|
||||
qrcode_benchmark,
|
||||
rss14_benchmark,
|
||||
rss_expanded_benchmark,
|
||||
upca_benchmark,
|
||||
upce_benchmark
|
||||
);
|
||||
criterion_main!(benches);
|
||||
@@ -1,6 +1,5 @@
|
||||
use proc_macro::TokenStream;
|
||||
use quote::quote;
|
||||
use syn;
|
||||
|
||||
#[proc_macro_derive(OneDReader)]
|
||||
pub fn one_d_reader_derive(input: TokenStream) -> TokenStream {
|
||||
@@ -23,27 +22,28 @@ fn impl_one_d_reader_macro(ast: &syn::DeriveInput) -> TokenStream {
|
||||
use crate::RXingResultMetadataValue;
|
||||
use crate::RXingResultPoint;
|
||||
use crate::Reader;
|
||||
use crate::Binarizer;
|
||||
|
||||
impl Reader for #name {
|
||||
fn decode(&mut self, image: &mut crate::BinaryBitmap) -> Result<crate::RXingResult, Exceptions> {
|
||||
fn decode<B: Binarizer>(&mut self, image: &mut crate::BinaryBitmap<B>) -> Result<crate::RXingResult, Exceptions> {
|
||||
self.decode_with_hints(image, &HashMap::new())
|
||||
}
|
||||
|
||||
// Note that we don't try rotation without the try harder flag, even if rotation was supported.
|
||||
fn decode_with_hints(
|
||||
fn decode_with_hints<B: Binarizer>(
|
||||
&mut self,
|
||||
image: &mut crate::BinaryBitmap,
|
||||
image: &mut crate::BinaryBitmap<B>,
|
||||
hints: &DecodingHintDictionary,
|
||||
) -> Result<crate::RXingResult, Exceptions> {
|
||||
if let Ok(res) = self.doDecode(image, hints) {
|
||||
if let Ok(res) = self._do_decode(image, hints) {
|
||||
Ok(res)
|
||||
}else {
|
||||
let tryHarder = hints.contains_key(&DecodeHintType::TRY_HARDER);
|
||||
if tryHarder && image.isRotateSupported() {
|
||||
let mut rotatedImage = image.rotateCounterClockwise();
|
||||
let mut result = self.doDecode(&mut rotatedImage, hints)?;
|
||||
if tryHarder && image.is_rotate_supported() {
|
||||
let mut rotated_image = image.rotate_counter_clockwise();
|
||||
let mut result = self._do_decode(&mut rotated_image, hints)?;
|
||||
// Record that we found it rotated 90 degrees CCW / 270 degrees CW
|
||||
let metadata = result.getRXingResultMetadata();
|
||||
let metadata = result.getRXingResultMetadata();
|
||||
let mut orientation = 270;
|
||||
if metadata.contains_key(&RXingResultMetadataType::ORIENTATION) {
|
||||
// But if we found it reversed in doDecode(), add in that result here:
|
||||
@@ -58,7 +58,7 @@ fn impl_one_d_reader_macro(ast: &syn::DeriveInput) -> TokenStream {
|
||||
// Update result points
|
||||
// let points = result.getRXingResultPoints();
|
||||
// if points != null {
|
||||
let height = rotatedImage.getHeight();
|
||||
let height = rotated_image.get_height();
|
||||
// for point in result.getRXingResultPointsMut().iter_mut() {
|
||||
let total_points = result.getRXingResultPoints().len();
|
||||
let points = result.getRXingResultPointsMut();
|
||||
@@ -93,13 +93,13 @@ fn impl_ean_reader_macro(ast: &syn::DeriveInput) -> TokenStream {
|
||||
let name = &ast.ident;
|
||||
let gen = quote! {
|
||||
impl super::OneDReader for #name {
|
||||
fn decodeRow(
|
||||
fn decode_row(
|
||||
&mut self,
|
||||
rowNumber: u32,
|
||||
row: &crate::common::BitArray,
|
||||
hints: &crate::DecodingHintDictionary,
|
||||
) -> Result<crate::RXingResult, crate::Exceptions> {
|
||||
self.decodeRowWithGuardRange(rowNumber, row, &self.findStartGuardPattern(row)?, hints)
|
||||
self.decodeRowWithGuardRange(rowNumber, row, &self.find_start_guard_pattern(row)?, hints)
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -52,10 +52,10 @@ fn test_no_crop() {
|
||||
false,
|
||||
)
|
||||
.unwrap();
|
||||
assert_equals(&Y, 0, &source.getMatrix(), 0, Y.len());
|
||||
assert_equals(&Y, 0, &source.get_matrix(), 0, Y.len());
|
||||
for r in 0..ROWS {
|
||||
// for (int r = 0; r < ROWS; r++) {
|
||||
assert_equals(&Y, r * COLS, &source.getRow(r), 0, COLS);
|
||||
assert_equals(&Y, r * COLS, &source.get_row(r), 0, COLS);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,8 +73,8 @@ fn test_crop() {
|
||||
false,
|
||||
)
|
||||
.unwrap();
|
||||
assert!(source.isCropSupported());
|
||||
let cropMatrix = source.getMatrix();
|
||||
assert!(source.is_crop_supported());
|
||||
let cropMatrix = source.get_matrix();
|
||||
for r in 0..ROWS - 2 {
|
||||
// for (int r = 0; r < ROWS - 2; r++) {
|
||||
assert_equals(
|
||||
@@ -87,7 +87,7 @@ fn test_crop() {
|
||||
}
|
||||
for r in 0..ROWS - 2 {
|
||||
// for (int r = 0; r < ROWS - 2; r++) {
|
||||
assert_equals(&Y, (r + 1) * COLS + 1, &source.getRow(r), 0, COLS - 2);
|
||||
assert_equals(&Y, (r + 1) * COLS + 1, &source.get_row(r), 0, COLS - 2);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ use std::collections::HashMap;
|
||||
use crate::{
|
||||
common::{DecoderRXingResult, DetectorRXingResult, Result},
|
||||
exceptions::Exceptions,
|
||||
BarcodeFormat, BinaryBitmap, DecodeHintType, DecodeHintValue, RXingResult,
|
||||
BarcodeFormat, Binarizer, BinaryBitmap, DecodeHintType, DecodeHintValue, RXingResult,
|
||||
RXingResultMetadataType, RXingResultMetadataValue, Reader,
|
||||
};
|
||||
|
||||
@@ -41,18 +41,18 @@ impl Reader for AztecReader {
|
||||
* @throws NotFoundException if a Data Matrix code cannot be found
|
||||
* @throws FormatException if a Data Matrix code cannot be decoded
|
||||
*/
|
||||
fn decode(&mut self, image: &mut BinaryBitmap) -> Result<RXingResult> {
|
||||
fn decode<B: Binarizer>(&mut self, image: &mut BinaryBitmap<B>) -> Result<RXingResult> {
|
||||
self.decode_with_hints(image, &HashMap::new())
|
||||
}
|
||||
|
||||
fn decode_with_hints(
|
||||
fn decode_with_hints<B: Binarizer>(
|
||||
&mut self,
|
||||
image: &mut BinaryBitmap,
|
||||
image: &mut BinaryBitmap<B>,
|
||||
hints: &HashMap<DecodeHintType, DecodeHintValue>,
|
||||
) -> Result<RXingResult> {
|
||||
// let notFoundException = None;
|
||||
// let formatException = None;
|
||||
let mut detector = Detector::new(image.getBlackMatrix());
|
||||
let mut detector = Detector::new(image.get_black_matrix());
|
||||
|
||||
// try {
|
||||
|
||||
|
||||
@@ -157,8 +157,8 @@ pub fn encode_bytes_with_charset(
|
||||
let bits = HighLevelEncoder::with_charset(data.into(), charset).encode()?;
|
||||
|
||||
// stuff bits and choose symbol size
|
||||
let ecc_bits = bits.getSize() as u32 * min_eccpercent / 100 + 11;
|
||||
let total_size_bits = bits.getSize() as u32 + ecc_bits;
|
||||
let ecc_bits = bits.get_size() as u32 * min_eccpercent / 100 + 11;
|
||||
let total_size_bits = bits.get_size() as u32 + ecc_bits;
|
||||
let mut compact;
|
||||
let mut layers: u32;
|
||||
let mut total_bits_in_layer_var;
|
||||
@@ -182,12 +182,12 @@ pub fn encode_bytes_with_charset(
|
||||
word_size = WORD_SIZE[layers as usize];
|
||||
let usable_bits_in_layers = total_bits_in_layer_var - (total_bits_in_layer_var % word_size);
|
||||
stuffed_bits = stuffBits(&bits, word_size as usize)?;
|
||||
if stuffed_bits.getSize() as u32 + ecc_bits > usable_bits_in_layers {
|
||||
if stuffed_bits.get_size() as u32 + ecc_bits > usable_bits_in_layers {
|
||||
return Err(Exceptions::illegal_argument_with(
|
||||
"Data to large for user specified layer",
|
||||
));
|
||||
}
|
||||
if compact && stuffed_bits.getSize() as u32 > word_size * 64 {
|
||||
if compact && stuffed_bits.get_size() as u32 > word_size * 64 {
|
||||
// Compact format only allows 64 data words, though C4 can hold more words than that
|
||||
return Err(Exceptions::illegal_argument_with(
|
||||
"Data to large for user specified layer",
|
||||
@@ -216,18 +216,18 @@ pub fn encode_bytes_with_charset(
|
||||
}
|
||||
// [Re]stuff the bits if this is the first opportunity, or if the
|
||||
// wordSize has changed
|
||||
if stuffed_bits.getSize() == 0 || word_size != WORD_SIZE[layers as usize] {
|
||||
if stuffed_bits.get_size() == 0 || word_size != WORD_SIZE[layers as usize] {
|
||||
word_size = WORD_SIZE[layers as usize];
|
||||
stuffed_bits = stuffBits(&bits, word_size as usize)?;
|
||||
}
|
||||
let usable_bits_in_layers =
|
||||
total_bits_in_layer_var - (total_bits_in_layer_var % word_size);
|
||||
if compact && stuffed_bits.getSize() as u32 > word_size * 64 {
|
||||
if compact && stuffed_bits.get_size() as u32 > word_size * 64 {
|
||||
// Compact format only allows 64 data words, though C4 can hold more words than that
|
||||
i += 1;
|
||||
continue;
|
||||
}
|
||||
if stuffed_bits.getSize() as u32 + ecc_bits <= usable_bits_in_layers {
|
||||
if stuffed_bits.get_size() as u32 + ecc_bits <= usable_bits_in_layers {
|
||||
break;
|
||||
}
|
||||
i += 1;
|
||||
@@ -240,7 +240,7 @@ pub fn encode_bytes_with_charset(
|
||||
)?;
|
||||
|
||||
// generate mode message
|
||||
let messageSizeInWords = stuffed_bits.getSize() as u32 / word_size;
|
||||
let messageSizeInWords = stuffed_bits.get_size() as u32 / word_size;
|
||||
let modeMessage = generateModeMessage(compact, layers, messageSizeInWords)?;
|
||||
|
||||
// allocate symbol
|
||||
@@ -429,7 +429,7 @@ fn drawModeMessage(matrix: &mut BitMatrix, compact: bool, matrixSize: u32, modeM
|
||||
|
||||
fn generateCheckWords(bitArray: &BitArray, totalBits: usize, wordSize: usize) -> Result<BitArray> {
|
||||
// bitArray is guaranteed to be a multiple of the wordSize, so no padding needed
|
||||
let message_size_in_words = bitArray.getSize() / wordSize;
|
||||
let message_size_in_words = bitArray.get_size() / wordSize;
|
||||
let mut rs = ReedSolomonEncoder::new(getGF(wordSize)?)?;
|
||||
let total_words = totalBits / wordSize;
|
||||
let mut message_words = bitsToWords(bitArray, wordSize, total_words);
|
||||
@@ -448,7 +448,7 @@ fn generateCheckWords(bitArray: &BitArray, totalBits: usize, wordSize: usize) ->
|
||||
fn bitsToWords(stuffedBits: &BitArray, wordSize: usize, totalWords: usize) -> Vec<i32> {
|
||||
let mut message = vec![0; totalWords];
|
||||
let mut i = 0;
|
||||
let n = stuffedBits.getSize() / wordSize;
|
||||
let n = stuffedBits.get_size() / wordSize;
|
||||
while i < n {
|
||||
// for (i = 0, n = stuffedBits.getSize() / wordSize; i < n; i++) {
|
||||
let mut value = 0;
|
||||
@@ -483,7 +483,7 @@ fn getGF(wordSize: usize) -> Result<GenericGFRef> {
|
||||
pub fn stuffBits(bits: &BitArray, word_size: usize) -> Result<BitArray> {
|
||||
let mut out = BitArray::new();
|
||||
|
||||
let n = bits.getSize() as isize;
|
||||
let n = bits.get_size() as isize;
|
||||
let mask = (1 << word_size) - 2;
|
||||
let mut i: isize = 0;
|
||||
while i < n {
|
||||
|
||||
@@ -21,7 +21,7 @@ pub fn toBitArray(bits: &str) -> BitArray {
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn toBooleanArray(bitArray: &BitArray) -> Vec<bool> {
|
||||
let mut result = vec![false; bitArray.getSize()];
|
||||
let mut result = vec![false; bitArray.get_size()];
|
||||
// for i in 0..result.len() {
|
||||
for (i, res) in result.iter_mut().enumerate() {
|
||||
// for (int i = 0; i < result.length; i++) {
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
//package com.google.zxing;
|
||||
|
||||
use std::{borrow::Cow, rc::Rc};
|
||||
use std::borrow::Cow;
|
||||
|
||||
use crate::{
|
||||
common::{BitArray, BitMatrix, Result},
|
||||
@@ -35,7 +35,9 @@ pub trait Binarizer {
|
||||
//private final LuminanceSource source;
|
||||
//fn new(source:dyn LuminanceSource) -> Self;
|
||||
|
||||
fn getLuminanceSource(&self) -> &Box<dyn LuminanceSource>;
|
||||
type Source: LuminanceSource;
|
||||
|
||||
fn get_luminance_source(&self) -> &Self::Source;
|
||||
|
||||
/**
|
||||
* Converts one row of luminance data to 1 bit data. May actually do the conversion, or return
|
||||
@@ -51,7 +53,7 @@ pub trait Binarizer {
|
||||
* @return The array of bits for this row (true means black).
|
||||
* @throws NotFoundException if row can't be binarized
|
||||
*/
|
||||
fn getBlackRow(&self, y: usize) -> Result<Cow<BitArray>>;
|
||||
fn get_black_row(&self, y: usize) -> Result<Cow<BitArray>>;
|
||||
|
||||
/**
|
||||
* Converts a 2D array of luminance data to 1 bit data. As above, assume this method is expensive
|
||||
@@ -62,7 +64,7 @@ pub trait Binarizer {
|
||||
* @return The 2D array of bits for the image (true means black).
|
||||
* @throws NotFoundException if image can't be binarized to make a matrix
|
||||
*/
|
||||
fn getBlackMatrix(&self) -> Result<&BitMatrix>;
|
||||
fn get_black_matrix(&self) -> Result<&BitMatrix>;
|
||||
|
||||
/**
|
||||
* Creates a new object with the same type as this Binarizer implementation, but with pristine
|
||||
@@ -72,9 +74,11 @@ pub trait Binarizer {
|
||||
* @param source The LuminanceSource this Binarizer will operate on.
|
||||
* @return A new concrete Binarizer implementation object.
|
||||
*/
|
||||
fn createBinarizer(&self, source: Box<dyn LuminanceSource>) -> Rc<dyn Binarizer>;
|
||||
fn create_binarizer(&self, source: Self::Source) -> Self
|
||||
where
|
||||
Self: Sized;
|
||||
|
||||
fn getWidth(&self) -> usize;
|
||||
fn get_width(&self) -> usize;
|
||||
|
||||
fn getHeight(&self) -> usize;
|
||||
fn get_height(&self) -> usize;
|
||||
}
|
||||
|
||||
@@ -16,11 +16,11 @@
|
||||
|
||||
//package com.google.zxing;
|
||||
|
||||
use std::{borrow::Cow, fmt, rc::Rc};
|
||||
use std::{borrow::Cow, fmt};
|
||||
|
||||
use crate::{
|
||||
common::{BitArray, BitMatrix, Result},
|
||||
Binarizer,
|
||||
Binarizer, LuminanceSource,
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -30,13 +30,13 @@ use crate::{
|
||||
* @author dswitkin@google.com (Daniel Switkin)
|
||||
*/
|
||||
|
||||
pub struct BinaryBitmap {
|
||||
binarizer: Rc<dyn Binarizer>,
|
||||
pub struct BinaryBitmap<B: Binarizer> {
|
||||
binarizer: B,
|
||||
matrix: Option<BitMatrix>,
|
||||
}
|
||||
|
||||
impl BinaryBitmap {
|
||||
pub fn new(binarizer: Rc<dyn Binarizer>) -> Self {
|
||||
impl<B: Binarizer> BinaryBitmap<B> {
|
||||
pub fn new(binarizer: B) -> Self {
|
||||
Self {
|
||||
matrix: None,
|
||||
binarizer,
|
||||
@@ -46,15 +46,15 @@ impl BinaryBitmap {
|
||||
/**
|
||||
* @return The width of the bitmap.
|
||||
*/
|
||||
pub fn getWidth(&self) -> usize {
|
||||
self.binarizer.getWidth()
|
||||
pub fn get_width(&self) -> usize {
|
||||
self.binarizer.get_width()
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The height of the bitmap.
|
||||
*/
|
||||
pub fn getHeight(&self) -> usize {
|
||||
self.binarizer.getHeight()
|
||||
pub fn get_height(&self) -> usize {
|
||||
self.binarizer.get_height()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -68,8 +68,8 @@ impl BinaryBitmap {
|
||||
* @return The array of bits for this row (true means black).
|
||||
* @throws NotFoundException if row can't be binarized
|
||||
*/
|
||||
pub fn getBlackRow(&self, y: usize) -> Result<Cow<BitArray>> {
|
||||
self.binarizer.getBlackRow(y)
|
||||
pub fn get_black_row(&self, y: usize) -> Result<Cow<BitArray>> {
|
||||
self.binarizer.get_black_row(y)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -83,14 +83,14 @@ impl BinaryBitmap {
|
||||
* @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 getBlackMatrixMut(&mut self) -> &mut BitMatrix {
|
||||
pub fn get_black_matrix_mut(&mut self) -> &mut BitMatrix {
|
||||
// The matrix is created on demand the first time it is requested, then cached. There are two
|
||||
// reasons for this:
|
||||
// 1. This work will never be done if the caller only installs 1D Reader objects, or if a
|
||||
// 1D Reader finds a barcode before the 2D Readers run.
|
||||
// 2. This work will only be done once even if the caller installs multiple 2D Readers.
|
||||
if self.matrix.is_none() {
|
||||
self.matrix = Some(self.binarizer.getBlackMatrix().unwrap().clone());
|
||||
self.matrix = Some(self.binarizer.get_black_matrix().unwrap().clone());
|
||||
}
|
||||
self.matrix.as_mut().unwrap()
|
||||
}
|
||||
@@ -106,14 +106,14 @@ impl BinaryBitmap {
|
||||
* @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 getBlackMatrix(&mut self) -> &BitMatrix {
|
||||
pub fn get_black_matrix(&mut self) -> &BitMatrix {
|
||||
// The matrix is created on demand the first time it is requested, then cached. There are two
|
||||
// reasons for this:
|
||||
// 1. This work will never be done if the caller only installs 1D Reader objects, or if a
|
||||
// 1D Reader finds a barcode before the 2D Readers run.
|
||||
// 2. This work will only be done once even if the caller installs multiple 2D Readers.
|
||||
if self.matrix.is_none() {
|
||||
self.matrix = Some(self.binarizer.getBlackMatrix().unwrap().clone())
|
||||
self.matrix = Some(self.binarizer.get_black_matrix().unwrap().clone())
|
||||
}
|
||||
self.matrix.as_ref().unwrap()
|
||||
}
|
||||
@@ -121,8 +121,8 @@ impl BinaryBitmap {
|
||||
/**
|
||||
* @return Whether this bitmap can be cropped.
|
||||
*/
|
||||
pub fn isCropSupported(&self) -> bool {
|
||||
self.binarizer.getLuminanceSource().isCropSupported()
|
||||
pub fn is_crop_supported(&self) -> bool {
|
||||
self.binarizer.get_luminance_source().is_crop_supported()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -137,22 +137,22 @@ impl BinaryBitmap {
|
||||
* @param height The height of the rectangle to crop.
|
||||
* @return A cropped version of this object.
|
||||
*/
|
||||
pub fn crop(&mut self, left: usize, top: usize, width: usize, height: usize) -> BinaryBitmap {
|
||||
pub fn crop(&mut self, left: usize, top: usize, width: usize, height: usize) -> Self {
|
||||
let newSource = self
|
||||
.binarizer
|
||||
.getLuminanceSource()
|
||||
.get_luminance_source()
|
||||
.crop(left, top, width, height);
|
||||
return BinaryBitmap::new(
|
||||
BinaryBitmap::new(
|
||||
self.binarizer
|
||||
.createBinarizer(newSource.expect("new lum source expected")),
|
||||
);
|
||||
.create_binarizer(newSource.expect("new lum source expected")),
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Whether this bitmap supports counter-clockwise rotation.
|
||||
*/
|
||||
pub fn isRotateSupported(&self) -> bool {
|
||||
return self.binarizer.getLuminanceSource().isRotateSupported();
|
||||
pub fn is_rotate_supported(&self) -> bool {
|
||||
return self.binarizer.get_luminance_source().is_rotate_supported();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -163,12 +163,15 @@ impl BinaryBitmap {
|
||||
*
|
||||
* @return A rotated version of this object.
|
||||
*/
|
||||
pub fn rotateCounterClockwise(&mut self) -> BinaryBitmap {
|
||||
let newSource = self.binarizer.getLuminanceSource().rotateCounterClockwise();
|
||||
return BinaryBitmap::new(
|
||||
pub fn rotate_counter_clockwise(&mut self) -> Self {
|
||||
let newSource = self
|
||||
.binarizer
|
||||
.get_luminance_source()
|
||||
.rotate_counter_clockwise();
|
||||
BinaryBitmap::new(
|
||||
self.binarizer
|
||||
.createBinarizer(newSource.expect("new lum source expected")),
|
||||
);
|
||||
.create_binarizer(newSource.expect("new lum source expected")),
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -179,19 +182,19 @@ impl BinaryBitmap {
|
||||
*
|
||||
* @return A rotated version of this object.
|
||||
*/
|
||||
pub fn rotateCounterClockwise45(&self) -> BinaryBitmap {
|
||||
pub fn rotate_counter_clockwise_45(&self) -> Self {
|
||||
let newSource = self
|
||||
.binarizer
|
||||
.getLuminanceSource()
|
||||
.rotateCounterClockwise45();
|
||||
return BinaryBitmap::new(
|
||||
.get_luminance_source()
|
||||
.rotate_counter_clockwise_45();
|
||||
BinaryBitmap::new(
|
||||
self.binarizer
|
||||
.createBinarizer(newSource.expect("new lum source expected")),
|
||||
);
|
||||
.create_binarizer(newSource.expect("new lum source expected")),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for BinaryBitmap {
|
||||
impl<B: Binarizer> fmt::Display for BinaryBitmap<B> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{:?}", self.matrix)
|
||||
}
|
||||
|
||||
@@ -88,8 +88,8 @@ impl BufferedImageLuminanceSource {
|
||||
}
|
||||
|
||||
impl LuminanceSource for BufferedImageLuminanceSource {
|
||||
fn getRow(&self, y: usize) -> Vec<u8> {
|
||||
let width = self.getWidth(); // - self.left as usize;
|
||||
fn get_row(&self, y: usize) -> Vec<u8> {
|
||||
let width = self.get_width(); // - self.left as usize;
|
||||
|
||||
let pixels: Vec<u8> = || -> Option<Vec<u8>> {
|
||||
Some(
|
||||
@@ -108,7 +108,7 @@ impl LuminanceSource for BufferedImageLuminanceSource {
|
||||
pixels
|
||||
}
|
||||
|
||||
fn getMatrix(&self) -> Vec<u8> {
|
||||
fn get_matrix(&self) -> Vec<u8> {
|
||||
if self.height == self.image.height() as usize && self.width == self.image.width() as usize
|
||||
{
|
||||
return self.image.as_bytes().to_vec();
|
||||
@@ -141,56 +141,50 @@ impl LuminanceSource for BufferedImageLuminanceSource {
|
||||
data
|
||||
}
|
||||
|
||||
fn getWidth(&self) -> usize {
|
||||
fn get_width(&self) -> usize {
|
||||
self.width
|
||||
}
|
||||
|
||||
fn getHeight(&self) -> usize {
|
||||
fn get_height(&self) -> usize {
|
||||
self.height
|
||||
}
|
||||
|
||||
fn is_crop_supported(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn crop(&self, left: usize, top: usize, width: usize, height: usize) -> Result<Self> {
|
||||
Ok(Self {
|
||||
image: self.image.clone(),
|
||||
width,
|
||||
height,
|
||||
left: self.left + left as u32,
|
||||
top: self.top + top as u32,
|
||||
})
|
||||
}
|
||||
|
||||
fn is_rotate_supported(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn invert(&mut self) {
|
||||
let mut img = (*self.image).clone();
|
||||
img.invert();
|
||||
self.image = Rc::new(img);
|
||||
}
|
||||
|
||||
fn isCropSupported(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn crop(
|
||||
&self,
|
||||
left: usize,
|
||||
top: usize,
|
||||
width: usize,
|
||||
height: usize,
|
||||
) -> Result<Box<dyn LuminanceSource>> {
|
||||
Ok(Box::new(Self {
|
||||
image: self.image.clone(),
|
||||
width,
|
||||
height,
|
||||
left: self.left + left as u32,
|
||||
top: self.top + top as u32,
|
||||
}))
|
||||
}
|
||||
|
||||
fn isRotateSupported(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn rotateCounterClockwise(&self) -> Result<Box<dyn LuminanceSource>> {
|
||||
fn rotate_counter_clockwise(&self) -> Result<Self> {
|
||||
let img = self.image.rotate270();
|
||||
Ok(Box::new(Self {
|
||||
Ok(Self {
|
||||
width: img.width() as usize,
|
||||
height: img.height() as usize,
|
||||
image: Rc::new(img),
|
||||
left: 0,
|
||||
top: 0,
|
||||
}))
|
||||
})
|
||||
}
|
||||
|
||||
fn rotateCounterClockwise45(&self) -> Result<Box<dyn LuminanceSource>> {
|
||||
fn rotate_counter_clockwise_45(&self) -> Result<Self> {
|
||||
let img = rotate_about_center(
|
||||
&self.image.to_luma8(),
|
||||
MINUS_45_IN_RADIANS,
|
||||
@@ -200,12 +194,12 @@ impl LuminanceSource for BufferedImageLuminanceSource {
|
||||
|
||||
let new_img = DynamicImage::from(img);
|
||||
|
||||
Ok(Box::new(Self {
|
||||
Ok(Self {
|
||||
width: new_img.width() as usize,
|
||||
height: new_img.height() as usize,
|
||||
image: Rc::new(new_img),
|
||||
left: 0,
|
||||
top: 0,
|
||||
}))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,12 +43,12 @@ fn test_get_set() {
|
||||
#[test]
|
||||
fn test_get_next_set1() {
|
||||
let array = BitArray::with_size(32);
|
||||
for i in 0..array.getSize() {
|
||||
for i in 0..array.get_size() {
|
||||
// for (int i = 0; i < array.getSize(); i++) {
|
||||
assert_eq!(32, array.getNextSet(i), "{i}");
|
||||
}
|
||||
let array = BitArray::with_size(33);
|
||||
for i in 0..array.getSize() {
|
||||
for i in 0..array.get_size() {
|
||||
// for (int i = 0; i < array.getSize(); i++) {
|
||||
assert_eq!(33, array.getNextSet(i), "{i}");
|
||||
}
|
||||
@@ -58,13 +58,13 @@ fn test_get_next_set1() {
|
||||
fn test_get_next_set2() {
|
||||
let mut array = BitArray::with_size(33);
|
||||
array.set(31);
|
||||
for i in 0..array.getSize() {
|
||||
for i in 0..array.get_size() {
|
||||
// for (int i = 0; i < array.getSize(); i++) {
|
||||
assert_eq!(if i <= 31 { 31 } else { 33 }, array.getNextSet(i), "{i}");
|
||||
}
|
||||
array = BitArray::with_size(33);
|
||||
array.set(32);
|
||||
for i in 0..array.getSize() {
|
||||
for i in 0..array.get_size() {
|
||||
// for (int i = 0; i < array.getSize(); i++) {
|
||||
assert_eq!(32, array.getNextSet(i), "{i}");
|
||||
}
|
||||
@@ -75,7 +75,7 @@ fn test_get_next_set3() {
|
||||
let mut array = BitArray::with_size(63);
|
||||
array.set(31);
|
||||
array.set(32);
|
||||
for i in 0..array.getSize() {
|
||||
for i in 0..array.get_size() {
|
||||
// for (int i = 0; i < array.getSize(); i++) {
|
||||
let expected;
|
||||
if i <= 31 {
|
||||
@@ -94,7 +94,7 @@ fn test_get_next_set4() {
|
||||
let mut array = BitArray::with_size(63);
|
||||
array.set(33);
|
||||
array.set(40);
|
||||
for i in 0..array.getSize() {
|
||||
for i in 0..array.get_size() {
|
||||
// for (int i = 0; i < array.getSize(); i++) {
|
||||
let expected;
|
||||
if i <= 33 {
|
||||
@@ -117,14 +117,14 @@ fn test_get_next_set5() {
|
||||
let numSet = r.gen_range(0..20);
|
||||
for _j in 0..numSet {
|
||||
// for (int j = 0; j < numSet; j++) {
|
||||
array.set(r.gen_range(0..array.getSize()));
|
||||
array.set(r.gen_range(0..array.get_size()));
|
||||
}
|
||||
let numQueries = r.gen_range(0..20);
|
||||
for _j in 0..numQueries {
|
||||
// for (int j = 0; j < numQueries; j++) {
|
||||
let query = r.gen_range(0..array.getSize());
|
||||
let query = r.gen_range(0..array.get_size());
|
||||
let mut expected = query;
|
||||
while expected < array.getSize() && !array.get(expected) {
|
||||
while expected < array.get_size() && !array.get(expected) {
|
||||
expected += 1;
|
||||
}
|
||||
let actual = array.getNextSet(query);
|
||||
|
||||
@@ -57,7 +57,7 @@ impl BitArray {
|
||||
Self { bits, size }
|
||||
}
|
||||
|
||||
pub fn getSize(&self) -> usize {
|
||||
pub fn get_size(&self) -> usize {
|
||||
self.size
|
||||
}
|
||||
|
||||
|
||||
@@ -156,12 +156,12 @@ fn test_get_row() {
|
||||
|
||||
// Should allocate
|
||||
let array = matrix.getRow(2);
|
||||
assert_eq!(102, array.getSize());
|
||||
assert_eq!(102, array.get_size());
|
||||
|
||||
// Should reallocate
|
||||
// let mut array2 = BitArray::with_size(60);
|
||||
let array2 = matrix.getRow(2);
|
||||
assert_eq!(102, array2.getSize());
|
||||
assert_eq!(102, array2.get_size());
|
||||
|
||||
// Should use provided object, with original BitArray size
|
||||
// let mut array3 = BitArray::with_size(200);
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
// import com.google.zxing.LuminanceSource;
|
||||
// import com.google.zxing.NotFoundException;
|
||||
|
||||
use std::{borrow::Cow, rc::Rc};
|
||||
use std::borrow::Cow;
|
||||
|
||||
use once_cell::unsync::OnceCell;
|
||||
|
||||
@@ -29,6 +29,10 @@ use crate::{Binarizer, Exceptions, LuminanceSource};
|
||||
|
||||
use super::{BitArray, BitMatrix};
|
||||
|
||||
const LUMINANCE_BITS: usize = 5;
|
||||
const LUMINANCE_SHIFT: usize = 8 - LUMINANCE_BITS;
|
||||
const LUMINANCE_BUCKETS: usize = 1 << LUMINANCE_BITS;
|
||||
|
||||
/**
|
||||
* 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
|
||||
@@ -40,34 +44,35 @@ use super::{BitArray, BitMatrix};
|
||||
* @author dswitkin@google.com (Daniel Switkin)
|
||||
* @author Sean Owen
|
||||
*/
|
||||
pub struct GlobalHistogramBinarizer {
|
||||
pub struct GlobalHistogramBinarizer<LS: LuminanceSource> {
|
||||
//_luminances: Vec<u8>,
|
||||
width: usize,
|
||||
height: usize,
|
||||
source: Box<dyn LuminanceSource>,
|
||||
source: LS,
|
||||
black_matrix: OnceCell<BitMatrix>,
|
||||
black_row_cache: Vec<OnceCell<BitArray>>,
|
||||
}
|
||||
|
||||
impl Binarizer for GlobalHistogramBinarizer {
|
||||
fn getLuminanceSource(&self) -> &Box<dyn LuminanceSource> {
|
||||
impl<LS: LuminanceSource> Binarizer for GlobalHistogramBinarizer<LS> {
|
||||
type Source = LS;
|
||||
|
||||
fn get_luminance_source(&self) -> &Self::Source {
|
||||
&self.source
|
||||
}
|
||||
|
||||
// Applies simple sharpening to the row data to improve performance of the 1D Readers.
|
||||
fn getBlackRow(&self, y: usize) -> Result<Cow<BitArray>> {
|
||||
fn get_black_row(&self, y: usize) -> Result<Cow<BitArray>> {
|
||||
let row = self.black_row_cache[y].get_or_try_init(|| {
|
||||
let source = self.getLuminanceSource();
|
||||
let width = source.getWidth();
|
||||
let source = self.get_luminance_source();
|
||||
let width = source.get_width();
|
||||
let mut row = BitArray::with_size(width);
|
||||
|
||||
// self.initArrays(width);
|
||||
let localLuminances = source.getRow(y);
|
||||
let mut localBuckets = [0; GlobalHistogramBinarizer::LUMINANCE_BUCKETS]; //self.buckets.clone();
|
||||
let localLuminances = source.get_row(y);
|
||||
let mut localBuckets = [0; LUMINANCE_BUCKETS]; //self.buckets.clone();
|
||||
for x in 0..width {
|
||||
// for (int x = 0; x < width; x++) {
|
||||
localBuckets[((localLuminances[x]) >> GlobalHistogramBinarizer::LUMINANCE_SHIFT)
|
||||
as usize] += 1;
|
||||
localBuckets[((localLuminances[x]) >> LUMINANCE_SHIFT) as usize] += 1;
|
||||
}
|
||||
let blackPoint = Self::estimateBlackPoint(&localBuckets)?;
|
||||
|
||||
@@ -102,63 +107,60 @@ impl Binarizer for GlobalHistogramBinarizer {
|
||||
}
|
||||
|
||||
// Does not sharpen the data, as this call is intended to only be used by 2D Readers.
|
||||
fn getBlackMatrix(&self) -> Result<&BitMatrix> {
|
||||
fn get_black_matrix(&self) -> Result<&BitMatrix> {
|
||||
let matrix = self
|
||||
.black_matrix
|
||||
.get_or_try_init(|| Self::build_black_matrix(&self.source))?;
|
||||
Ok(matrix)
|
||||
}
|
||||
|
||||
fn createBinarizer(&self, source: Box<dyn crate::LuminanceSource>) -> Rc<dyn Binarizer> {
|
||||
Rc::new(GlobalHistogramBinarizer::new(source))
|
||||
fn create_binarizer(&self, source: LS) -> Self {
|
||||
Self::new(source)
|
||||
}
|
||||
|
||||
fn getWidth(&self) -> usize {
|
||||
fn get_width(&self) -> usize {
|
||||
self.width
|
||||
}
|
||||
|
||||
fn getHeight(&self) -> usize {
|
||||
fn get_height(&self) -> usize {
|
||||
self.height
|
||||
}
|
||||
}
|
||||
|
||||
impl GlobalHistogramBinarizer {
|
||||
const LUMINANCE_BITS: usize = 5;
|
||||
const LUMINANCE_SHIFT: usize = 8 - GlobalHistogramBinarizer::LUMINANCE_BITS;
|
||||
const LUMINANCE_BUCKETS: usize = 1 << GlobalHistogramBinarizer::LUMINANCE_BITS;
|
||||
impl<LS: LuminanceSource> GlobalHistogramBinarizer<LS> {
|
||||
// const EMPTY: [u8; 0] = [0; 0];
|
||||
|
||||
pub fn new(source: Box<dyn LuminanceSource>) -> Self {
|
||||
pub fn new(source: LS) -> Self {
|
||||
Self {
|
||||
//_luminances: vec![0; source.getWidth()],
|
||||
width: source.getWidth(),
|
||||
height: source.getHeight(),
|
||||
width: source.get_width(),
|
||||
height: source.get_height(),
|
||||
black_matrix: OnceCell::new(),
|
||||
black_row_cache: vec![OnceCell::default(); source.getHeight()],
|
||||
black_row_cache: vec![OnceCell::default(); source.get_height()],
|
||||
source,
|
||||
}
|
||||
}
|
||||
|
||||
fn build_black_matrix(source: &Box<dyn LuminanceSource>) -> Result<BitMatrix> {
|
||||
fn build_black_matrix(source: &LS) -> Result<BitMatrix> {
|
||||
// let source = source.getLuminanceSource();
|
||||
let width = source.getWidth();
|
||||
let height = source.getHeight();
|
||||
let width = source.get_width();
|
||||
let height = source.get_height();
|
||||
let mut matrix = BitMatrix::new(width as u32, height as u32)?;
|
||||
|
||||
// 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.initArrays(width);
|
||||
let mut localBuckets = [0; GlobalHistogramBinarizer::LUMINANCE_BUCKETS]; //self.buckets.clone();
|
||||
let mut localBuckets = [0; LUMINANCE_BUCKETS]; //self.buckets.clone();
|
||||
for y in 1..5 {
|
||||
// for (int y = 1; y < 5; y++) {
|
||||
let row = height * y / 5;
|
||||
let localLuminances = source.getRow(row);
|
||||
let localLuminances = source.get_row(row);
|
||||
let right = (width * 4) / 5;
|
||||
let mut x = width / 5;
|
||||
while x < right {
|
||||
// for (int x = width / 5; x < right; x++) {
|
||||
let pixel = localLuminances[x];
|
||||
localBuckets[(pixel >> GlobalHistogramBinarizer::LUMINANCE_SHIFT) as usize] += 1;
|
||||
localBuckets[(pixel >> LUMINANCE_SHIFT) as usize] += 1;
|
||||
x += 1;
|
||||
}
|
||||
}
|
||||
@@ -167,7 +169,7 @@ impl GlobalHistogramBinarizer {
|
||||
// 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 localLuminances = source.getMatrix();
|
||||
let localLuminances = source.get_matrix();
|
||||
for y in 0..height {
|
||||
// for (int y = 0; y < height; y++) {
|
||||
let offset = y * width;
|
||||
@@ -255,6 +257,6 @@ impl GlobalHistogramBinarizer {
|
||||
x -= 1;
|
||||
}
|
||||
|
||||
Ok((bestValley as u32) << GlobalHistogramBinarizer::LUMINANCE_SHIFT)
|
||||
Ok((bestValley as u32) << LUMINANCE_SHIFT)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
// import com.google.zxing.LuminanceSource;
|
||||
// import com.google.zxing.NotFoundException;
|
||||
|
||||
use std::{borrow::Cow, rc::Rc};
|
||||
use std::borrow::Cow;
|
||||
|
||||
use once_cell::unsync::OnceCell;
|
||||
|
||||
@@ -46,20 +46,22 @@ use super::{BitArray, BitMatrix, GlobalHistogramBinarizer};
|
||||
*
|
||||
* @author dswitkin@google.com (Daniel Switkin)
|
||||
*/
|
||||
pub struct HybridBinarizer {
|
||||
pub struct HybridBinarizer<LS: LuminanceSource> {
|
||||
//width: usize,
|
||||
//height: usize,
|
||||
//source: Box<dyn LuminanceSource>,
|
||||
ghb: GlobalHistogramBinarizer,
|
||||
ghb: GlobalHistogramBinarizer<LS>,
|
||||
black_matrix: OnceCell<BitMatrix>,
|
||||
}
|
||||
impl Binarizer for HybridBinarizer {
|
||||
fn getLuminanceSource(&self) -> &Box<dyn LuminanceSource> {
|
||||
self.ghb.getLuminanceSource()
|
||||
impl<LS: LuminanceSource> Binarizer for HybridBinarizer<LS> {
|
||||
type Source = LS;
|
||||
|
||||
fn get_luminance_source(&self) -> &LS {
|
||||
self.ghb.get_luminance_source()
|
||||
}
|
||||
|
||||
fn getBlackRow(&self, y: usize) -> Result<Cow<BitArray>> {
|
||||
self.ghb.getBlackRow(y)
|
||||
fn get_black_row(&self, y: usize) -> Result<Cow<BitArray>> {
|
||||
self.ghb.get_black_row(y)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -67,35 +69,36 @@ impl Binarizer for HybridBinarizer {
|
||||
* 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.
|
||||
*/
|
||||
fn getBlackMatrix(&self) -> Result<&BitMatrix> {
|
||||
fn get_black_matrix(&self) -> Result<&BitMatrix> {
|
||||
let matrix = self
|
||||
.black_matrix
|
||||
.get_or_try_init(|| Self::calculateBlackMatrix(&self.ghb))?;
|
||||
Ok(matrix)
|
||||
}
|
||||
|
||||
fn createBinarizer(&self, source: Box<dyn LuminanceSource>) -> Rc<dyn Binarizer> {
|
||||
Rc::new(HybridBinarizer::new(source))
|
||||
fn create_binarizer(&self, source: LS) -> Self {
|
||||
Self::new(source)
|
||||
}
|
||||
|
||||
fn getWidth(&self) -> usize {
|
||||
self.ghb.getWidth()
|
||||
fn get_width(&self) -> usize {
|
||||
self.ghb.get_width()
|
||||
}
|
||||
|
||||
fn getHeight(&self) -> usize {
|
||||
self.ghb.getHeight()
|
||||
fn get_height(&self) -> usize {
|
||||
self.ghb.get_height()
|
||||
}
|
||||
}
|
||||
impl HybridBinarizer {
|
||||
// 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: usize = 3;
|
||||
const BLOCK_SIZE: usize = 1 << HybridBinarizer::BLOCK_SIZE_POWER; // ...0100...00
|
||||
const BLOCK_SIZE_MASK: usize = HybridBinarizer::BLOCK_SIZE - 1; // ...0011...11
|
||||
const MINIMUM_DIMENSION: usize = HybridBinarizer::BLOCK_SIZE * 5;
|
||||
const MIN_DYNAMIC_RANGE: usize = 24;
|
||||
|
||||
pub fn new(source: Box<dyn LuminanceSource>) -> Self {
|
||||
// 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: usize = 3;
|
||||
const BLOCK_SIZE: usize = 1 << BLOCK_SIZE_POWER; // ...0100...00
|
||||
const BLOCK_SIZE_MASK: usize = BLOCK_SIZE - 1; // ...0011...11
|
||||
const MINIMUM_DIMENSION: usize = BLOCK_SIZE * 5;
|
||||
const MIN_DYNAMIC_RANGE: usize = 24;
|
||||
|
||||
impl<LS: LuminanceSource> HybridBinarizer<LS> {
|
||||
pub fn new(source: LS) -> Self {
|
||||
let ghb = GlobalHistogramBinarizer::new(source);
|
||||
Self {
|
||||
black_matrix: OnceCell::new(),
|
||||
@@ -103,21 +106,21 @@ impl HybridBinarizer {
|
||||
}
|
||||
}
|
||||
|
||||
fn calculateBlackMatrix(ghb: &GlobalHistogramBinarizer) -> Result<BitMatrix> {
|
||||
fn calculateBlackMatrix<LS2: LuminanceSource>(
|
||||
ghb: &GlobalHistogramBinarizer<LS2>,
|
||||
) -> Result<BitMatrix> {
|
||||
// let matrix;
|
||||
let source = ghb.getLuminanceSource();
|
||||
let width = source.getWidth();
|
||||
let height = source.getHeight();
|
||||
let matrix = if width >= HybridBinarizer::MINIMUM_DIMENSION
|
||||
&& height >= HybridBinarizer::MINIMUM_DIMENSION
|
||||
{
|
||||
let luminances = source.getMatrix();
|
||||
let mut sub_width = width >> HybridBinarizer::BLOCK_SIZE_POWER;
|
||||
if (width & HybridBinarizer::BLOCK_SIZE_MASK) != 0 {
|
||||
let source = ghb.get_luminance_source();
|
||||
let width = source.get_width();
|
||||
let height = source.get_height();
|
||||
let matrix = if width >= MINIMUM_DIMENSION && height >= MINIMUM_DIMENSION {
|
||||
let luminances = source.get_matrix();
|
||||
let mut sub_width = width >> BLOCK_SIZE_POWER;
|
||||
if (width & BLOCK_SIZE_MASK) != 0 {
|
||||
sub_width += 1;
|
||||
}
|
||||
let mut sub_height = height >> HybridBinarizer::BLOCK_SIZE_POWER;
|
||||
if (height & HybridBinarizer::BLOCK_SIZE_MASK) != 0 {
|
||||
let mut sub_height = height >> BLOCK_SIZE_POWER;
|
||||
if (height & BLOCK_SIZE_MASK) != 0 {
|
||||
sub_height += 1;
|
||||
}
|
||||
let black_points = Self::calculateBlackPoints(
|
||||
@@ -141,7 +144,7 @@ impl HybridBinarizer {
|
||||
Ok(new_matrix)
|
||||
} else {
|
||||
// If the image is too small, fall back to the global histogram approach.
|
||||
let m = ghb.getBlackMatrix()?;
|
||||
let m = ghb.get_black_matrix()?;
|
||||
Ok(m.clone())
|
||||
};
|
||||
// dbg!(matrix.to_string());
|
||||
@@ -162,18 +165,18 @@ impl HybridBinarizer {
|
||||
black_points: &[Vec<u32>],
|
||||
matrix: &mut BitMatrix,
|
||||
) {
|
||||
let maxYOffset = height - HybridBinarizer::BLOCK_SIZE as u32;
|
||||
let maxXOffset = width - HybridBinarizer::BLOCK_SIZE as u32;
|
||||
let maxYOffset = height - BLOCK_SIZE as u32;
|
||||
let maxXOffset = width - BLOCK_SIZE as u32;
|
||||
for y in 0..sub_height {
|
||||
// for (int y = 0; y < subHeight; y++) {
|
||||
let mut yoffset = y << HybridBinarizer::BLOCK_SIZE_POWER;
|
||||
let mut yoffset = y << BLOCK_SIZE_POWER;
|
||||
if yoffset > maxYOffset {
|
||||
yoffset = maxYOffset;
|
||||
}
|
||||
let top = Self::cap(y, sub_height - 3);
|
||||
for x in 0..sub_width {
|
||||
// for (int x = 0; x < subWidth; x++) {
|
||||
let mut xoffset = x << HybridBinarizer::BLOCK_SIZE_POWER;
|
||||
let mut xoffset = x << BLOCK_SIZE_POWER;
|
||||
if xoffset > maxXOffset {
|
||||
xoffset = maxXOffset;
|
||||
}
|
||||
@@ -215,9 +218,9 @@ impl HybridBinarizer {
|
||||
matrix: &mut BitMatrix,
|
||||
) {
|
||||
let mut offset = yoffset * stride + xoffset;
|
||||
for y in 0..HybridBinarizer::BLOCK_SIZE {
|
||||
for y in 0..BLOCK_SIZE {
|
||||
// for (int y = 0, offset = yoffset * stride + xoffset; y < HybridBinarizer::BLOCK_SIZE; y++, offset += stride) {
|
||||
for x in 0..HybridBinarizer::BLOCK_SIZE {
|
||||
for x in 0..BLOCK_SIZE {
|
||||
// for (int x = 0; x < HybridBinarizer::BLOCK_SIZE; x++) {
|
||||
// Comparison needs to be <= so that black == 0 pixels are black even if the threshold is 0.
|
||||
if luminances[offset as usize + x] as u32 <= threshold {
|
||||
@@ -240,18 +243,18 @@ impl HybridBinarizer {
|
||||
width: u32,
|
||||
height: u32,
|
||||
) -> Vec<Vec<u32>> {
|
||||
let maxYOffset = height as usize - HybridBinarizer::BLOCK_SIZE;
|
||||
let maxXOffset = width as usize - HybridBinarizer::BLOCK_SIZE;
|
||||
let maxYOffset = height as usize - BLOCK_SIZE;
|
||||
let maxXOffset = width as usize - BLOCK_SIZE;
|
||||
let mut blackPoints = vec![vec![0; subWidth as usize]; subHeight as usize];
|
||||
for y in 0..subHeight {
|
||||
// for (int y = 0; y < subHeight; y++) {
|
||||
let mut yoffset = y << HybridBinarizer::BLOCK_SIZE_POWER;
|
||||
let mut yoffset = y << BLOCK_SIZE_POWER;
|
||||
if yoffset > maxYOffset as u32 {
|
||||
yoffset = maxYOffset as u32;
|
||||
}
|
||||
for x in 0..subWidth {
|
||||
// for (int x = 0; x < subWidth; x++) {
|
||||
let mut xoffset = x << HybridBinarizer::BLOCK_SIZE_POWER;
|
||||
let mut xoffset = x << BLOCK_SIZE_POWER;
|
||||
if xoffset > maxXOffset as u32 {
|
||||
xoffset = maxXOffset as u32;
|
||||
}
|
||||
@@ -261,9 +264,9 @@ impl HybridBinarizer {
|
||||
|
||||
let mut offset = yoffset * width + xoffset;
|
||||
let mut yy = 0;
|
||||
while yy < HybridBinarizer::BLOCK_SIZE {
|
||||
while yy < BLOCK_SIZE {
|
||||
// for (int yy = 0, offset = yoffset * width + xoffset; yy < HybridBinarizer::BLOCK_SIZE; yy++, offset += width) {
|
||||
for xx in 0..HybridBinarizer::BLOCK_SIZE {
|
||||
for xx in 0..BLOCK_SIZE {
|
||||
// for (int xx = 0; xx < HybridBinarizer::BLOCK_SIZE; xx++) {
|
||||
let pixel = luminances[offset as usize + xx];
|
||||
sum += pixel as u32;
|
||||
@@ -276,13 +279,13 @@ impl HybridBinarizer {
|
||||
}
|
||||
}
|
||||
// short-circuit min/max tests once dynamic range is met
|
||||
if (max - min) as usize > HybridBinarizer::MIN_DYNAMIC_RANGE {
|
||||
if (max - min) as usize > MIN_DYNAMIC_RANGE {
|
||||
// finish the rest of the rows quickly
|
||||
offset += width;
|
||||
yy += 1;
|
||||
while yy < HybridBinarizer::BLOCK_SIZE {
|
||||
while yy < BLOCK_SIZE {
|
||||
// for (yy++, offset += width; yy < HybridBinarizer::BLOCK_SIZE; yy++, offset += width) {
|
||||
for xx in 0..HybridBinarizer::BLOCK_SIZE {
|
||||
for xx in 0..BLOCK_SIZE {
|
||||
// for (int xx = 0; xx < BLOCK_SIZE; xx++) {
|
||||
sum += luminances[offset as usize + xx] as u32;
|
||||
}
|
||||
@@ -296,8 +299,8 @@ impl HybridBinarizer {
|
||||
}
|
||||
|
||||
// The default estimate is the average of the values in the block.
|
||||
let mut average = sum >> (HybridBinarizer::BLOCK_SIZE_POWER * 2);
|
||||
if (max - min) as usize <= HybridBinarizer::MIN_DYNAMIC_RANGE {
|
||||
let mut average = sum >> (BLOCK_SIZE_POWER * 2);
|
||||
if (max - min) as usize <= 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.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use std::{borrow::Cow, rc::Rc};
|
||||
use std::borrow::Cow;
|
||||
|
||||
use image::{DynamicImage, ImageBuffer, Luma};
|
||||
use once_cell::sync::OnceCell;
|
||||
@@ -8,18 +8,18 @@ use crate::{Binarizer, Exceptions, LuminanceSource};
|
||||
|
||||
use super::{BitArray, BitMatrix};
|
||||
|
||||
pub struct OtsuLevelBinarizer {
|
||||
pub struct OtsuLevelBinarizer<LS: LuminanceSource> {
|
||||
width: usize,
|
||||
height: usize,
|
||||
source: Box<dyn LuminanceSource>,
|
||||
source: LS,
|
||||
black_matrix: OnceCell<BitMatrix>,
|
||||
black_row_cache: Vec<OnceCell<BitArray>>,
|
||||
}
|
||||
|
||||
impl OtsuLevelBinarizer {
|
||||
fn generate_threshold_matrix(source: &dyn LuminanceSource) -> Result<BitMatrix> {
|
||||
impl<LS: LuminanceSource> OtsuLevelBinarizer<LS> {
|
||||
fn generate_threshold_matrix<LS2: LuminanceSource>(source: &LS2) -> Result<BitMatrix> {
|
||||
let image_buffer = {
|
||||
let Some(buff) : Option<ImageBuffer<Luma<u8>,Vec<u8>>> = ImageBuffer::from_vec(source.getWidth() as u32, source.getHeight() as u32, source.getMatrix()) else {
|
||||
let Some(buff) : Option<ImageBuffer<Luma<u8>,Vec<u8>>> = ImageBuffer::from_vec(source.get_width() as u32, source.get_height() as u32, source.get_matrix()) else {
|
||||
return Err(Exceptions::ILLEGAL_ARGUMENT)
|
||||
};
|
||||
buff
|
||||
@@ -34,50 +34,49 @@ impl OtsuLevelBinarizer {
|
||||
dynamic_filtered.try_into()
|
||||
}
|
||||
|
||||
pub fn new(source: Box<dyn LuminanceSource>) -> Self {
|
||||
pub fn new(source: LS) -> Self {
|
||||
Self {
|
||||
width: source.getWidth(),
|
||||
height: source.getHeight(),
|
||||
black_row_cache: vec![OnceCell::default(); source.getHeight()],
|
||||
width: source.get_width(),
|
||||
height: source.get_height(),
|
||||
black_row_cache: vec![OnceCell::default(); source.get_height()],
|
||||
source,
|
||||
black_matrix: OnceCell::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Binarizer for OtsuLevelBinarizer {
|
||||
fn getLuminanceSource(&self) -> &Box<dyn crate::LuminanceSource> {
|
||||
impl<LS: LuminanceSource> Binarizer for OtsuLevelBinarizer<LS> {
|
||||
type Source = LS;
|
||||
|
||||
fn get_luminance_source(&self) -> &LS {
|
||||
&self.source
|
||||
}
|
||||
|
||||
fn getBlackRow(&self, y: usize) -> Result<std::borrow::Cow<super::BitArray>> {
|
||||
fn get_black_row(&self, y: usize) -> Result<Cow<BitArray>> {
|
||||
let row = self.black_row_cache[y].get_or_try_init(|| {
|
||||
let matrix = self.getBlackMatrix()?;
|
||||
let matrix = self.get_black_matrix()?;
|
||||
Ok(matrix.getRow(y as u32))
|
||||
})?;
|
||||
|
||||
Ok(Cow::Borrowed(row))
|
||||
}
|
||||
|
||||
fn getBlackMatrix(&self) -> Result<&super::BitMatrix> {
|
||||
fn get_black_matrix(&self) -> Result<&BitMatrix> {
|
||||
let matrix = self
|
||||
.black_matrix
|
||||
.get_or_try_init(|| Self::generate_threshold_matrix(self.source.as_ref()))?;
|
||||
.get_or_try_init(|| Self::generate_threshold_matrix(&self.source))?;
|
||||
Ok(matrix)
|
||||
}
|
||||
|
||||
fn createBinarizer(
|
||||
&self,
|
||||
source: Box<dyn crate::LuminanceSource>,
|
||||
) -> std::rc::Rc<dyn Binarizer> {
|
||||
Rc::new(Self::new(source))
|
||||
fn create_binarizer(&self, source: LS) -> Self {
|
||||
Self::new(source)
|
||||
}
|
||||
|
||||
fn getWidth(&self) -> usize {
|
||||
fn get_width(&self) -> usize {
|
||||
self.width
|
||||
}
|
||||
|
||||
fn getHeight(&self) -> usize {
|
||||
fn get_height(&self) -> usize {
|
||||
self.height
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ use std::collections::HashMap;
|
||||
|
||||
use crate::{
|
||||
common::{BitMatrix, DecoderRXingResult, DetectorRXingResult, Result},
|
||||
BarcodeFormat, DecodeHintType, DecodeHintValue, Exceptions, RXingResult,
|
||||
BarcodeFormat, Binarizer, DecodeHintType, DecodeHintValue, Exceptions, RXingResult,
|
||||
RXingResultMetadataType, RXingResultMetadataValue, Reader,
|
||||
};
|
||||
|
||||
@@ -52,7 +52,10 @@ impl Reader for DataMatrixReader {
|
||||
* @throws FormatException if a Data Matrix code cannot be decoded
|
||||
* @throws ChecksumException if error correction fails
|
||||
*/
|
||||
fn decode(&mut self, image: &mut crate::BinaryBitmap) -> Result<crate::RXingResult> {
|
||||
fn decode<B: Binarizer>(
|
||||
&mut self,
|
||||
image: &mut crate::BinaryBitmap<B>,
|
||||
) -> Result<crate::RXingResult> {
|
||||
self.decode_with_hints(image, &HashMap::new())
|
||||
}
|
||||
|
||||
@@ -64,9 +67,9 @@ impl Reader for DataMatrixReader {
|
||||
* @throws FormatException if a Data Matrix code cannot be decoded
|
||||
* @throws ChecksumException if error correction fails
|
||||
*/
|
||||
fn decode_with_hints(
|
||||
fn decode_with_hints<B: Binarizer>(
|
||||
&mut self,
|
||||
image: &mut crate::BinaryBitmap,
|
||||
image: &mut crate::BinaryBitmap<B>,
|
||||
hints: &crate::DecodingHintDictionary,
|
||||
) -> Result<crate::RXingResult> {
|
||||
let try_harder = matches!(
|
||||
@@ -76,14 +79,14 @@ impl Reader for DataMatrixReader {
|
||||
let decoderRXingResult;
|
||||
let mut points = Vec::new();
|
||||
if hints.contains_key(&DecodeHintType::PURE_BARCODE) {
|
||||
let bits = self.extractPureBits(image.getBlackMatrix())?;
|
||||
let bits = self.extractPureBits(image.get_black_matrix())?;
|
||||
decoderRXingResult = DECODER.decode(&bits)?;
|
||||
points.clear();
|
||||
} else {
|
||||
//Result<DatamatrixDetectorResult, Exceptions>
|
||||
decoderRXingResult = if let Ok(fnd) = || -> Result<DecoderRXingResult> {
|
||||
let detectorRXingResult =
|
||||
zxing_cpp_detector::detect(image.getBlackMatrix(), try_harder, true)?;
|
||||
zxing_cpp_detector::detect(image.get_black_matrix(), try_harder, true)?;
|
||||
let decoded = DECODER.decode(detectorRXingResult.getBits())?;
|
||||
points = detectorRXingResult.getPoints().to_vec();
|
||||
Ok(decoded)
|
||||
@@ -91,14 +94,14 @@ impl Reader for DataMatrixReader {
|
||||
fnd
|
||||
} else if try_harder {
|
||||
if let Ok(fnd) = || -> Result<DecoderRXingResult> {
|
||||
let detectorRXingResult = Detector::new(image.getBlackMatrix())?.detect()?;
|
||||
let detectorRXingResult = Detector::new(image.get_black_matrix())?.detect()?;
|
||||
let decoded = DECODER.decode(detectorRXingResult.getBits())?;
|
||||
points = detectorRXingResult.getPoints().to_vec();
|
||||
Ok(decoded)
|
||||
}() {
|
||||
fnd
|
||||
} else {
|
||||
let bits = self.extractPureBits(image.getBlackMatrix())?;
|
||||
let bits = self.extractPureBits(image.get_black_matrix())?;
|
||||
DECODER.decode(&bits)?
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -2,7 +2,6 @@ use std::{
|
||||
collections::{HashMap, HashSet},
|
||||
io::Write,
|
||||
path::PathBuf,
|
||||
rc::Rc,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
@@ -58,9 +57,7 @@ pub fn detect_in_svg_with_hints(
|
||||
.or_insert(DecodeHintValue::TryHarder(true));
|
||||
|
||||
multi_format_reader.decode_with_hints(
|
||||
&mut BinaryBitmap::new(Rc::new(HybridBinarizer::new(Box::new(
|
||||
SVGLuminanceSource::new(&svg_data)?,
|
||||
)))),
|
||||
&mut BinaryBitmap::new(HybridBinarizer::new(SVGLuminanceSource::new(&svg_data)?)),
|
||||
hints,
|
||||
)
|
||||
}
|
||||
@@ -101,9 +98,7 @@ pub fn detect_multiple_in_svg_with_hints(
|
||||
.or_insert(DecodeHintValue::TryHarder(true));
|
||||
|
||||
scanner.decode_multiple_with_hints(
|
||||
&mut BinaryBitmap::new(Rc::new(HybridBinarizer::new(Box::new(
|
||||
SVGLuminanceSource::new(&svg_data)?,
|
||||
)))),
|
||||
&mut BinaryBitmap::new(HybridBinarizer::new(SVGLuminanceSource::new(&svg_data)?)),
|
||||
hints,
|
||||
)
|
||||
}
|
||||
@@ -136,9 +131,7 @@ pub fn detect_in_file_with_hints(
|
||||
.or_insert(DecodeHintValue::TryHarder(true));
|
||||
|
||||
multi_format_reader.decode_with_hints(
|
||||
&mut BinaryBitmap::new(Rc::new(HybridBinarizer::new(Box::new(
|
||||
BufferedImageLuminanceSource::new(img),
|
||||
)))),
|
||||
&mut BinaryBitmap::new(HybridBinarizer::new(BufferedImageLuminanceSource::new(img))),
|
||||
hints,
|
||||
)
|
||||
}
|
||||
@@ -163,9 +156,7 @@ pub fn detect_multiple_in_file_with_hints(
|
||||
.or_insert(DecodeHintValue::TryHarder(true));
|
||||
|
||||
scanner.decode_multiple_with_hints(
|
||||
&mut BinaryBitmap::new(Rc::new(HybridBinarizer::new(Box::new(
|
||||
BufferedImageLuminanceSource::new(img),
|
||||
)))),
|
||||
&mut BinaryBitmap::new(HybridBinarizer::new(BufferedImageLuminanceSource::new(img))),
|
||||
hints,
|
||||
)
|
||||
}
|
||||
@@ -200,9 +191,9 @@ pub fn detect_in_luma_with_hints(
|
||||
.or_insert(DecodeHintValue::TryHarder(true));
|
||||
|
||||
multi_format_reader.decode_with_hints(
|
||||
&mut BinaryBitmap::new(Rc::new(HybridBinarizer::new(Box::new(
|
||||
Luma8LuminanceSource::new(luma, width, height),
|
||||
)))),
|
||||
&mut BinaryBitmap::new(HybridBinarizer::new(Luma8LuminanceSource::new(
|
||||
luma, width, height,
|
||||
))),
|
||||
hints,
|
||||
)
|
||||
}
|
||||
@@ -225,9 +216,9 @@ pub fn detect_multiple_in_luma_with_hints(
|
||||
.or_insert(DecodeHintValue::TryHarder(true));
|
||||
|
||||
scanner.decode_multiple_with_hints(
|
||||
&mut BinaryBitmap::new(Rc::new(HybridBinarizer::new(Box::new(
|
||||
Luma8LuminanceSource::new(luma, width, height),
|
||||
)))),
|
||||
&mut BinaryBitmap::new(HybridBinarizer::new(Luma8LuminanceSource::new(
|
||||
luma, width, height,
|
||||
))),
|
||||
hints,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ pub struct Luma8LuminanceSource {
|
||||
original_dimension: (u32, u32),
|
||||
}
|
||||
impl LuminanceSource for Luma8LuminanceSource {
|
||||
fn getRow(&self, y: usize) -> Vec<u8> {
|
||||
fn get_row(&self, y: usize) -> Vec<u8> {
|
||||
self.data
|
||||
.chunks_exact(self.original_dimension.0 as usize)
|
||||
.skip(y + self.origin.1 as usize)
|
||||
@@ -27,7 +27,7 @@ impl LuminanceSource for Luma8LuminanceSource {
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn getMatrix(&self) -> Vec<u8> {
|
||||
fn get_matrix(&self) -> Vec<u8> {
|
||||
self.data
|
||||
.iter()
|
||||
.skip((self.original_dimension.0 * self.origin.1) as usize)
|
||||
@@ -38,7 +38,7 @@ impl LuminanceSource for Luma8LuminanceSource {
|
||||
.flat_map(|f| {
|
||||
f.iter()
|
||||
.skip((self.origin.0) as usize)
|
||||
.take(self.getWidth())
|
||||
.take(self.get_width())
|
||||
.copied()
|
||||
}) // flatten this all out
|
||||
.copied() // copy it over so that it's u8
|
||||
@@ -46,11 +46,11 @@ impl LuminanceSource for Luma8LuminanceSource {
|
||||
.collect() // collect into a vec
|
||||
}
|
||||
|
||||
fn getWidth(&self) -> usize {
|
||||
fn get_width(&self) -> usize {
|
||||
self.dimensions.0 as usize
|
||||
}
|
||||
|
||||
fn getHeight(&self) -> usize {
|
||||
fn get_height(&self) -> usize {
|
||||
self.dimensions.1 as usize
|
||||
}
|
||||
|
||||
@@ -58,31 +58,25 @@ impl LuminanceSource for Luma8LuminanceSource {
|
||||
self.inverted = !self.inverted;
|
||||
}
|
||||
|
||||
fn isCropSupported(&self) -> bool {
|
||||
fn is_crop_supported(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn crop(
|
||||
&self,
|
||||
left: usize,
|
||||
top: usize,
|
||||
width: usize,
|
||||
height: usize,
|
||||
) -> Result<Box<dyn LuminanceSource>> {
|
||||
Ok(Box::new(Self {
|
||||
fn crop(&self, left: usize, top: usize, width: usize, height: usize) -> Result<Self> {
|
||||
Ok(Self {
|
||||
dimensions: (width as u32, height as u32),
|
||||
origin: (left as u32, top as u32),
|
||||
data: self.data.clone(),
|
||||
inverted: self.inverted,
|
||||
original_dimension: self.original_dimension,
|
||||
}))
|
||||
})
|
||||
}
|
||||
|
||||
fn isRotateSupported(&self) -> bool {
|
||||
fn is_rotate_supported(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn rotateCounterClockwise(&self) -> Result<Box<dyn LuminanceSource>> {
|
||||
fn rotate_counter_clockwise(&self) -> Result<Self> {
|
||||
let mut new_matrix = Self {
|
||||
dimensions: self.dimensions,
|
||||
origin: self.origin,
|
||||
@@ -92,10 +86,10 @@ impl LuminanceSource for Luma8LuminanceSource {
|
||||
};
|
||||
new_matrix.transpose();
|
||||
new_matrix.reverseColumns();
|
||||
Ok(Box::new(new_matrix))
|
||||
Ok(new_matrix)
|
||||
}
|
||||
|
||||
fn rotateCounterClockwise45(&self) -> Result<Box<dyn LuminanceSource>> {
|
||||
fn rotate_counter_clockwise_45(&self) -> Result<Self> {
|
||||
Err(crate::Exceptions::unsupported_operation_with(
|
||||
"This luminance source does not support rotation by 45 degrees.",
|
||||
))
|
||||
@@ -104,12 +98,12 @@ impl LuminanceSource for Luma8LuminanceSource {
|
||||
|
||||
impl Luma8LuminanceSource {
|
||||
fn reverseColumns(&mut self) {
|
||||
for i in 0..self.getWidth() {
|
||||
for i in 0..self.get_width() {
|
||||
let mut j = 0;
|
||||
let mut k = self.getWidth() - 1;
|
||||
let mut k = self.get_width() - 1;
|
||||
while j < k {
|
||||
let offset_a = (self.getWidth() * i) + j;
|
||||
let offset_b = (self.getWidth() * i) + k;
|
||||
let offset_a = (self.get_width() * i) + j;
|
||||
let offset_b = (self.get_width() * i) + k;
|
||||
self.data.swap(offset_a, offset_b);
|
||||
j += 1;
|
||||
k -= 1;
|
||||
@@ -118,10 +112,10 @@ impl Luma8LuminanceSource {
|
||||
}
|
||||
|
||||
fn transpose(&mut self) {
|
||||
for i in 0..self.getHeight() {
|
||||
for j in i..self.getWidth() {
|
||||
let offset_a = (self.getWidth() * i) + j;
|
||||
let offset_b = (self.getWidth() * j) + i;
|
||||
for i in 0..self.get_height() {
|
||||
for j in i..self.get_width() {
|
||||
let offset_a = (self.get_width() * i) + j;
|
||||
let offset_b = (self.get_width() * j) + i;
|
||||
self.data.swap(offset_a, offset_b);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ pub trait LuminanceSource {
|
||||
* Always use the returned object, and ignore the .length of the array.
|
||||
* @return An array containing the luminance data.
|
||||
*/
|
||||
fn getRow(&self, y: usize) -> Vec<u8>;
|
||||
fn get_row(&self, y: usize) -> Vec<u8>;
|
||||
|
||||
/**
|
||||
* Fetches luminance data for the underlying bitmap. Values should be fetched using:
|
||||
@@ -56,22 +56,22 @@ pub trait LuminanceSource {
|
||||
* larger than width * height bytes on some platforms. Do not modify the contents
|
||||
* of the result.
|
||||
*/
|
||||
fn getMatrix(&self) -> Vec<u8>;
|
||||
fn get_matrix(&self) -> Vec<u8>;
|
||||
|
||||
/**
|
||||
* @return The width of the bitmap.
|
||||
*/
|
||||
fn getWidth(&self) -> usize;
|
||||
fn get_width(&self) -> usize;
|
||||
|
||||
/**
|
||||
* @return The height of the bitmap.
|
||||
*/
|
||||
fn getHeight(&self) -> usize;
|
||||
fn get_height(&self) -> usize;
|
||||
|
||||
/**
|
||||
* @return Whether this subclass supports cropping.
|
||||
*/
|
||||
fn isCropSupported(&self) -> bool {
|
||||
fn is_crop_supported(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
@@ -85,13 +85,10 @@ pub trait LuminanceSource {
|
||||
* @param height The height of the rectangle to crop.
|
||||
* @return A cropped version of this object.
|
||||
*/
|
||||
fn crop(
|
||||
&self,
|
||||
_left: usize,
|
||||
_top: usize,
|
||||
_width: usize,
|
||||
_height: usize,
|
||||
) -> Result<Box<dyn LuminanceSource>> {
|
||||
fn crop(&self, _left: usize, _top: usize, _width: usize, _height: usize) -> Result<Self>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
Err(Exceptions::unsupported_operation_with(
|
||||
"This luminance source does not support cropping.",
|
||||
))
|
||||
@@ -100,7 +97,7 @@ pub trait LuminanceSource {
|
||||
/**
|
||||
* @return Whether this subclass supports counter-clockwise rotation.
|
||||
*/
|
||||
fn isRotateSupported(&self) -> bool {
|
||||
fn is_rotate_supported(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
@@ -118,7 +115,10 @@ pub trait LuminanceSource {
|
||||
*
|
||||
* @return A rotated version of this object.
|
||||
*/
|
||||
fn rotateCounterClockwise(&self) -> Result<Box<dyn LuminanceSource>> {
|
||||
fn rotate_counter_clockwise(&self) -> Result<Self>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
Err(Exceptions::unsupported_operation_with(
|
||||
"This luminance source does not support rotation by 90 degrees.",
|
||||
))
|
||||
@@ -130,7 +130,10 @@ pub trait LuminanceSource {
|
||||
*
|
||||
* @return A rotated version of this object.
|
||||
*/
|
||||
fn rotateCounterClockwise45(&self) -> Result<Box<dyn LuminanceSource>> {
|
||||
fn rotate_counter_clockwise_45(&self) -> Result<Self>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
Err(Exceptions::unsupported_operation_with(
|
||||
"This luminance source does not support rotation by 45 degrees.",
|
||||
))
|
||||
|
||||
@@ -1143,8 +1143,8 @@ mod detector_test {
|
||||
let filename = image;
|
||||
let img = image::open(filename).unwrap();
|
||||
let lum_src = BufferedImageLuminanceSource::new(img);
|
||||
let binarizer = HybridBinarizer::new(Box::new(lum_src));
|
||||
let bitmatrix = binarizer.getBlackMatrix().unwrap();
|
||||
let binarizer = HybridBinarizer::new(lum_src);
|
||||
let bitmatrix = binarizer.get_black_matrix().unwrap();
|
||||
|
||||
// let i: image::DynamicImage = bitmatrix.into();
|
||||
// i.save("dbgfle.png").expect("should write image");
|
||||
|
||||
@@ -18,7 +18,7 @@ use std::collections::HashMap;
|
||||
|
||||
use crate::{
|
||||
common::{BitMatrix, DetectorRXingResult, Result},
|
||||
BarcodeFormat, DecodeHintType, DecodeHintValue, Exceptions, RXingResult,
|
||||
BarcodeFormat, Binarizer, DecodeHintType, DecodeHintValue, Exceptions, RXingResult,
|
||||
RXingResultMetadataType, Reader,
|
||||
};
|
||||
|
||||
@@ -41,7 +41,10 @@ impl Reader for MaxiCodeReader {
|
||||
* @throws FormatException if a MaxiCode cannot be decoded
|
||||
* @throws ChecksumException if error correction fails
|
||||
*/
|
||||
fn decode(&mut self, image: &mut crate::BinaryBitmap) -> Result<crate::RXingResult> {
|
||||
fn decode<B: Binarizer>(
|
||||
&mut self,
|
||||
image: &mut crate::BinaryBitmap<B>,
|
||||
) -> Result<crate::RXingResult> {
|
||||
self.decode_with_hints(image, &HashMap::new())
|
||||
}
|
||||
|
||||
@@ -53,9 +56,9 @@ impl Reader for MaxiCodeReader {
|
||||
* @throws FormatException if a MaxiCode cannot be decoded
|
||||
* @throws ChecksumException if error correction fails
|
||||
*/
|
||||
fn decode_with_hints(
|
||||
fn decode_with_hints<B: Binarizer>(
|
||||
&mut self,
|
||||
image: &mut crate::BinaryBitmap,
|
||||
image: &mut crate::BinaryBitmap<B>,
|
||||
hints: &crate::DecodingHintDictionary,
|
||||
) -> Result<crate::RXingResult> {
|
||||
// Note that MaxiCode reader effectively always assumes PURE_BARCODE mode
|
||||
@@ -68,12 +71,12 @@ impl Reader for MaxiCodeReader {
|
||||
let mut rotation = None;
|
||||
|
||||
let decoderRXingResult = if try_harder {
|
||||
let result = detector::detect(image.getBlackMatrixMut(), try_harder)?;
|
||||
let result = detector::detect(image.get_black_matrix_mut(), try_harder)?;
|
||||
rotation = Some(result.rotation());
|
||||
let parsed_result = detector::read_bits(result.getBits())?;
|
||||
maxicode_decoder::decode_with_hints(&parsed_result, hints)?
|
||||
} else {
|
||||
let bits = Self::extractPureBits(image.getBlackMatrix())?;
|
||||
let bits = Self::extractPureBits(image.get_black_matrix())?;
|
||||
maxicode_decoder::decode_with_hints(&bits, hints)?
|
||||
};
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use crate::common::Result;
|
||||
use crate::{point, Exceptions, Point, RXingResult, Reader};
|
||||
use crate::{point, Binarizer, Exceptions, Point, RXingResult, Reader};
|
||||
|
||||
/**
|
||||
* This class attempts to decode a barcode from an image, not by scanning the whole image,
|
||||
@@ -30,17 +30,17 @@ use crate::{point, Exceptions, Point, RXingResult, Reader};
|
||||
*/
|
||||
pub struct ByQuadrantReader<T: Reader>(T);
|
||||
impl<T: Reader> Reader for ByQuadrantReader<T> {
|
||||
fn decode(&mut self, image: &mut crate::BinaryBitmap) -> Result<crate::RXingResult> {
|
||||
fn decode<B: Binarizer>(&mut self, image: &mut crate::BinaryBitmap<B>) -> Result<RXingResult> {
|
||||
self.decode_with_hints(image, &HashMap::new())
|
||||
}
|
||||
|
||||
fn decode_with_hints(
|
||||
fn decode_with_hints<B: Binarizer>(
|
||||
&mut self,
|
||||
image: &mut crate::BinaryBitmap,
|
||||
image: &mut crate::BinaryBitmap<B>,
|
||||
hints: &crate::DecodingHintDictionary,
|
||||
) -> Result<crate::RXingResult> {
|
||||
let width = image.getWidth();
|
||||
let height = image.getHeight();
|
||||
let width = image.get_width();
|
||||
let height = image.get_height();
|
||||
let halfWidth = width / 2;
|
||||
let halfHeight = height / 2;
|
||||
|
||||
|
||||
@@ -17,8 +17,8 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use crate::{
|
||||
common::Result, point, BinaryBitmap, DecodingHintDictionary, Exceptions, Point, RXingResult,
|
||||
Reader,
|
||||
common::Result, point, Binarizer, BinaryBitmap, DecodingHintDictionary, Exceptions, Point,
|
||||
RXingResult, Reader,
|
||||
};
|
||||
|
||||
use super::MultipleBarcodeReader;
|
||||
@@ -41,20 +41,20 @@ use super::MultipleBarcodeReader;
|
||||
pub struct GenericMultipleBarcodeReader<T: Reader>(T);
|
||||
|
||||
impl<T: Reader> MultipleBarcodeReader for GenericMultipleBarcodeReader<T> {
|
||||
fn decode_multiple(
|
||||
fn decode_multiple<B: Binarizer>(
|
||||
&mut self,
|
||||
image: &mut crate::BinaryBitmap,
|
||||
) -> Result<Vec<crate::RXingResult>> {
|
||||
image: &mut BinaryBitmap<B>,
|
||||
) -> Result<Vec<RXingResult>> {
|
||||
self.decode_multiple_with_hints(image, &HashMap::new())
|
||||
}
|
||||
|
||||
fn decode_multiple_with_hints(
|
||||
fn decode_multiple_with_hints<B: Binarizer>(
|
||||
&mut self,
|
||||
image: &mut crate::BinaryBitmap,
|
||||
hints: &crate::DecodingHintDictionary,
|
||||
) -> Result<Vec<crate::RXingResult>> {
|
||||
image: &mut BinaryBitmap<B>,
|
||||
hints: &DecodingHintDictionary,
|
||||
) -> Result<Vec<RXingResult>> {
|
||||
let mut results = Vec::new();
|
||||
self.doDecodeMultiple(image, hints, &mut results, 0, 0, 0);
|
||||
self.do_decode_multiple(image, hints, &mut results, 0, 0, 0);
|
||||
if results.is_empty() {
|
||||
return Err(Exceptions::NOT_FOUND);
|
||||
}
|
||||
@@ -69,9 +69,9 @@ impl<T: Reader> GenericMultipleBarcodeReader<T> {
|
||||
Self(delegate)
|
||||
}
|
||||
|
||||
fn doDecodeMultiple(
|
||||
fn do_decode_multiple<B: Binarizer>(
|
||||
&mut self,
|
||||
image: &mut BinaryBitmap,
|
||||
image: &mut BinaryBitmap<B>,
|
||||
hints: &DecodingHintDictionary,
|
||||
results: &mut Vec<RXingResult>,
|
||||
xOffset: u32,
|
||||
@@ -105,8 +105,8 @@ impl<T: Reader> GenericMultipleBarcodeReader<T> {
|
||||
return;
|
||||
}
|
||||
|
||||
let width = image.getWidth();
|
||||
let height = image.getHeight();
|
||||
let width = image.get_width();
|
||||
let height = image.get_height();
|
||||
let mut minX: f32 = width as f32;
|
||||
let mut minY: f32 = height as f32;
|
||||
let mut maxX: f32 = 0.0;
|
||||
@@ -133,7 +133,7 @@ impl<T: Reader> GenericMultipleBarcodeReader<T> {
|
||||
|
||||
// Decode left of barcode
|
||||
if minX > Self::MIN_DIMENSION_TO_RECUR {
|
||||
self.doDecodeMultiple(
|
||||
self.do_decode_multiple(
|
||||
&mut image.crop(0, 0, minX as usize, height),
|
||||
hints,
|
||||
results,
|
||||
@@ -144,7 +144,7 @@ impl<T: Reader> GenericMultipleBarcodeReader<T> {
|
||||
}
|
||||
// Decode above barcode
|
||||
if minY > Self::MIN_DIMENSION_TO_RECUR {
|
||||
self.doDecodeMultiple(
|
||||
self.do_decode_multiple(
|
||||
&mut image.crop(0, 0, width, minY as usize),
|
||||
hints,
|
||||
results,
|
||||
@@ -155,7 +155,7 @@ impl<T: Reader> GenericMultipleBarcodeReader<T> {
|
||||
}
|
||||
// Decode right of barcode
|
||||
if maxX < (width as f32) - Self::MIN_DIMENSION_TO_RECUR {
|
||||
self.doDecodeMultiple(
|
||||
self.do_decode_multiple(
|
||||
&mut image.crop(maxX as usize, 0, width - maxX as usize, height),
|
||||
hints,
|
||||
results,
|
||||
@@ -166,7 +166,7 @@ impl<T: Reader> GenericMultipleBarcodeReader<T> {
|
||||
}
|
||||
// Decode below barcode
|
||||
if maxY < (height as f32) - Self::MIN_DIMENSION_TO_RECUR {
|
||||
self.doDecodeMultiple(
|
||||
self.do_decode_multiple(
|
||||
&mut image.crop(0, maxY as usize, width, height - maxY as usize),
|
||||
hints,
|
||||
results,
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
use std::{collections::HashSet, path::PathBuf, rc::Rc};
|
||||
use std::{collections::HashSet, path::PathBuf};
|
||||
|
||||
use crate::{
|
||||
common::HybridBinarizer, BarcodeFormat, BinaryBitmap, BufferedImageLuminanceSource,
|
||||
@@ -38,7 +38,7 @@ fn testMulti() {
|
||||
.decode()
|
||||
.expect("must decode");
|
||||
let source = BufferedImageLuminanceSource::new(image);
|
||||
let mut bitmap = BinaryBitmap::new(Rc::new(HybridBinarizer::new(Box::new(source))));
|
||||
let mut bitmap = BinaryBitmap::new(HybridBinarizer::new(source));
|
||||
|
||||
let mut reader = GenericMultipleBarcodeReader::new(MultiFormatReader::default());
|
||||
let results = reader
|
||||
@@ -65,7 +65,7 @@ fn testMultiQR() {
|
||||
.decode()
|
||||
.expect("must decode");
|
||||
let source = BufferedImageLuminanceSource::new(image);
|
||||
let mut bitmap = BinaryBitmap::new(Rc::new(HybridBinarizer::new(Box::new(source))));
|
||||
let mut bitmap = BinaryBitmap::new(HybridBinarizer::new(source));
|
||||
|
||||
let mut reader = GenericMultipleBarcodeReader::new(MultiFormatReader::default());
|
||||
let results = reader
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
use crate::{common::Result, BinaryBitmap, DecodingHintDictionary, RXingResult};
|
||||
use crate::{common::Result, Binarizer, BinaryBitmap, DecodingHintDictionary, RXingResult};
|
||||
|
||||
/**
|
||||
* Implementation of this interface attempt to read several barcodes from one image.
|
||||
@@ -23,11 +23,14 @@ use crate::{common::Result, BinaryBitmap, DecodingHintDictionary, RXingResult};
|
||||
* @author Sean Owen
|
||||
*/
|
||||
pub trait MultipleBarcodeReader {
|
||||
fn decode_multiple(&mut self, image: &mut BinaryBitmap) -> Result<Vec<RXingResult>>;
|
||||
|
||||
fn decode_multiple_with_hints(
|
||||
fn decode_multiple<B: Binarizer>(
|
||||
&mut self,
|
||||
image: &mut BinaryBitmap,
|
||||
image: &mut BinaryBitmap<B>,
|
||||
) -> Result<Vec<RXingResult>>;
|
||||
|
||||
fn decode_multiple_with_hints<B: Binarizer>(
|
||||
&mut self,
|
||||
image: &mut BinaryBitmap<B>,
|
||||
hints: &DecodingHintDictionary,
|
||||
) -> Result<Vec<RXingResult>>;
|
||||
}
|
||||
|
||||
@@ -23,7 +23,8 @@ use crate::{
|
||||
decoder::{self, QRCodeDecoderMetaData},
|
||||
QRCodeReader,
|
||||
},
|
||||
BarcodeFormat, Exceptions, RXingResult, RXingResultMetadataType, RXingResultMetadataValue,
|
||||
BarcodeFormat, Binarizer, Exceptions, RXingResult, RXingResultMetadataType,
|
||||
RXingResultMetadataValue,
|
||||
};
|
||||
|
||||
use super::detector::MultiDetector;
|
||||
@@ -37,20 +38,21 @@ use super::detector::MultiDetector;
|
||||
#[derive(Default)]
|
||||
pub struct QRCodeMultiReader(QRCodeReader);
|
||||
impl MultipleBarcodeReader for QRCodeMultiReader {
|
||||
fn decode_multiple(
|
||||
fn decode_multiple<B: Binarizer>(
|
||||
&mut self,
|
||||
image: &mut crate::BinaryBitmap,
|
||||
) -> Result<Vec<crate::RXingResult>> {
|
||||
image: &mut crate::BinaryBitmap<B>,
|
||||
) -> Result<Vec<RXingResult>> {
|
||||
self.decode_multiple_with_hints(image, &HashMap::new())
|
||||
}
|
||||
|
||||
fn decode_multiple_with_hints(
|
||||
fn decode_multiple_with_hints<B: Binarizer>(
|
||||
&mut self,
|
||||
image: &mut crate::BinaryBitmap,
|
||||
image: &mut crate::BinaryBitmap<B>,
|
||||
hints: &crate::DecodingHintDictionary,
|
||||
) -> Result<Vec<crate::RXingResult>> {
|
||||
) -> Result<Vec<RXingResult>> {
|
||||
let mut results = Vec::new();
|
||||
let detectorRXingResults = MultiDetector::new(image.getBlackMatrix()).detectMulti(hints)?;
|
||||
let detectorRXingResults =
|
||||
MultiDetector::new(image.get_black_matrix()).detectMulti(hints)?;
|
||||
for detectorRXingResult in detectorRXingResults {
|
||||
let mut proc = || -> Result<()> {
|
||||
let decoderRXingResult = decoder::qrcode_decoder::decode_bitmatrix_with_hints(
|
||||
@@ -219,7 +221,7 @@ mod multi_qr_code_test_case {
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
use std::{collections::HashSet, path::PathBuf, rc::Rc};
|
||||
use std::{collections::HashSet, path::PathBuf};
|
||||
|
||||
use image;
|
||||
|
||||
@@ -247,7 +249,7 @@ mod multi_qr_code_test_case {
|
||||
.decode()
|
||||
.expect("must decode");
|
||||
let source = BufferedImageLuminanceSource::new(image);
|
||||
let mut bitmap = BinaryBitmap::new(Rc::new(HybridBinarizer::new(Box::new(source))));
|
||||
let mut bitmap = BinaryBitmap::new(HybridBinarizer::new(source));
|
||||
|
||||
let mut reader = QRCodeMultiReader::new();
|
||||
let results = reader.decode_multiple(&mut bitmap).expect("must decode");
|
||||
|
||||
@@ -14,14 +14,14 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
|
||||
use crate::common::Result;
|
||||
use crate::{
|
||||
aztec::AztecReader, datamatrix::DataMatrixReader, maxicode::MaxiCodeReader,
|
||||
oned::MultiFormatOneDReader, pdf417::PDF417Reader, qrcode::QRCodeReader, BarcodeFormat,
|
||||
BinaryBitmap, DecodeHintType, DecodeHintValue, DecodingHintDictionary, Exceptions, RXingResult,
|
||||
Reader,
|
||||
Binarizer, BinaryBitmap, DecodeHintType, DecodeHintValue, DecodingHintDictionary, Exceptions,
|
||||
RXingResult, Reader,
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -35,7 +35,9 @@ use crate::{
|
||||
#[derive(Default)]
|
||||
pub struct MultiFormatReader {
|
||||
hints: DecodingHintDictionary,
|
||||
readers: Vec<Box<dyn Reader>>,
|
||||
possible_formats: HashSet<BarcodeFormat>,
|
||||
try_harder: bool,
|
||||
one_d_reader: MultiFormatOneDReader,
|
||||
}
|
||||
|
||||
impl Reader for MultiFormatReader {
|
||||
@@ -48,8 +50,8 @@ impl Reader for MultiFormatReader {
|
||||
* @return The contents of the image
|
||||
* @throws NotFoundException Any errors which occurred
|
||||
*/
|
||||
fn decode(&mut self, image: &mut crate::BinaryBitmap) -> Result<crate::RXingResult> {
|
||||
self.set_ints(&HashMap::new());
|
||||
fn decode<B: Binarizer>(&mut self, image: &mut BinaryBitmap<B>) -> Result<RXingResult> {
|
||||
self.set_hints(&HashMap::new());
|
||||
self.decode_internal(image)
|
||||
}
|
||||
|
||||
@@ -61,19 +63,17 @@ impl Reader for MultiFormatReader {
|
||||
* @return The contents of the image
|
||||
* @throws NotFoundException Any errors which occurred
|
||||
*/
|
||||
fn decode_with_hints(
|
||||
fn decode_with_hints<B: Binarizer>(
|
||||
&mut self,
|
||||
image: &mut crate::BinaryBitmap,
|
||||
hints: &crate::DecodingHintDictionary,
|
||||
) -> Result<crate::RXingResult> {
|
||||
self.set_ints(hints);
|
||||
image: &mut BinaryBitmap<B>,
|
||||
hints: &DecodingHintDictionary,
|
||||
) -> Result<RXingResult> {
|
||||
self.set_hints(hints);
|
||||
self.decode_internal(image)
|
||||
}
|
||||
|
||||
fn reset(&mut self) {
|
||||
for reader in self.readers.iter_mut() {
|
||||
reader.reset();
|
||||
}
|
||||
self.one_d_reader.reset();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,10 +86,13 @@ impl MultiFormatReader {
|
||||
* @return The contents of the image
|
||||
* @throws NotFoundException Any errors which occurred
|
||||
*/
|
||||
pub fn decode_with_state(&mut self, image: &mut BinaryBitmap) -> Result<RXingResult> {
|
||||
pub fn decode_with_state<B: Binarizer>(
|
||||
&mut self,
|
||||
image: &mut BinaryBitmap<B>,
|
||||
) -> Result<RXingResult> {
|
||||
// Make sure to set up the default state so we don't crash
|
||||
if self.readers.is_empty() {
|
||||
self.set_ints(&HashMap::new());
|
||||
if self.possible_formats.is_empty() {
|
||||
self.set_hints(&HashMap::new());
|
||||
}
|
||||
self.decode_internal(image)
|
||||
}
|
||||
@@ -101,92 +104,121 @@ impl MultiFormatReader {
|
||||
*
|
||||
* @param hints The set of hints to use for subsequent calls to decode(image)
|
||||
*/
|
||||
pub fn set_ints(&mut self, hints: &DecodingHintDictionary) {
|
||||
pub fn set_hints(&mut self, hints: &DecodingHintDictionary) {
|
||||
self.hints = hints.clone();
|
||||
|
||||
let tryHarder = matches!(
|
||||
self.try_harder = matches!(
|
||||
self.hints.get(&DecodeHintType::TRY_HARDER),
|
||||
Some(DecodeHintValue::TryHarder(true))
|
||||
);
|
||||
|
||||
let formats = hints.get(&DecodeHintType::POSSIBLE_FORMATS);
|
||||
let mut readers: Vec<Box<dyn Reader>> = Vec::new();
|
||||
if let Some(DecodeHintValue::PossibleFormats(formats)) = formats {
|
||||
let addOneDReader = formats.contains(&BarcodeFormat::UPC_A)
|
||||
|| formats.contains(&BarcodeFormat::UPC_E)
|
||||
|| formats.contains(&BarcodeFormat::EAN_13)
|
||||
|| formats.contains(&BarcodeFormat::EAN_8)
|
||||
|| formats.contains(&BarcodeFormat::CODABAR)
|
||||
|| formats.contains(&BarcodeFormat::CODE_39)
|
||||
|| formats.contains(&BarcodeFormat::CODE_93)
|
||||
|| formats.contains(&BarcodeFormat::CODE_128)
|
||||
|| formats.contains(&BarcodeFormat::ITF)
|
||||
|| formats.contains(&BarcodeFormat::RSS_14)
|
||||
|| formats.contains(&BarcodeFormat::RSS_EXPANDED);
|
||||
// Put 1D readers upfront in "normal" mode
|
||||
if addOneDReader && !tryHarder {
|
||||
readers.push(Box::new(MultiFormatOneDReader::new(hints)));
|
||||
}
|
||||
if formats.contains(&BarcodeFormat::QR_CODE) {
|
||||
readers.push(Box::<QRCodeReader>::default());
|
||||
}
|
||||
if formats.contains(&BarcodeFormat::DATA_MATRIX) {
|
||||
readers.push(Box::<DataMatrixReader>::default());
|
||||
}
|
||||
if formats.contains(&BarcodeFormat::AZTEC) {
|
||||
readers.push(Box::<AztecReader>::default());
|
||||
}
|
||||
if formats.contains(&BarcodeFormat::PDF_417) {
|
||||
readers.push(Box::<PDF417Reader>::default());
|
||||
}
|
||||
if formats.contains(&BarcodeFormat::MAXICODE) {
|
||||
readers.push(Box::<MaxiCodeReader>::default());
|
||||
}
|
||||
// At end in "try harder" mode
|
||||
if addOneDReader && tryHarder {
|
||||
readers.push(Box::new(MultiFormatOneDReader::new(hints)));
|
||||
}
|
||||
}
|
||||
if readers.is_empty() {
|
||||
if !tryHarder {
|
||||
readers.push(Box::new(MultiFormatOneDReader::new(hints)));
|
||||
}
|
||||
|
||||
readers.push(Box::<QRCodeReader>::default());
|
||||
readers.push(Box::<DataMatrixReader>::default());
|
||||
readers.push(Box::<AztecReader>::default());
|
||||
readers.push(Box::<PDF417Reader>::default());
|
||||
readers.push(Box::<MaxiCodeReader>::default());
|
||||
|
||||
if tryHarder {
|
||||
readers.push(Box::new(MultiFormatOneDReader::new(hints)));
|
||||
}
|
||||
}
|
||||
self.readers = readers;
|
||||
self.possible_formats = if let Some(DecodeHintValue::PossibleFormats(formats)) =
|
||||
hints.get(&DecodeHintType::POSSIBLE_FORMATS)
|
||||
{
|
||||
formats.clone()
|
||||
} else {
|
||||
HashSet::new()
|
||||
};
|
||||
self.one_d_reader = MultiFormatOneDReader::new(hints);
|
||||
}
|
||||
|
||||
pub fn decode_internal(&mut self, image: &mut BinaryBitmap) -> Result<RXingResult> {
|
||||
if !self.readers.is_empty() {
|
||||
for reader in self.readers.iter_mut() {
|
||||
let res = reader.decode_with_hints(image, &self.hints);
|
||||
if res.is_ok() {
|
||||
return res;
|
||||
}
|
||||
}
|
||||
if matches!(
|
||||
self.hints.get(&DecodeHintType::ALSO_INVERTED),
|
||||
Some(DecodeHintValue::AlsoInverted(true))
|
||||
) {
|
||||
// Calling all readers again with inverted image
|
||||
image.getBlackMatrixMut().flip_self();
|
||||
for reader in self.readers.iter_mut() {
|
||||
let res = reader.decode_with_hints(image, &self.hints);
|
||||
if res.is_ok() {
|
||||
return res;
|
||||
}
|
||||
}
|
||||
pub fn decode_internal<B: Binarizer>(
|
||||
&mut self,
|
||||
image: &mut BinaryBitmap<B>,
|
||||
) -> Result<RXingResult> {
|
||||
let res = self.decode_formats(image);
|
||||
if res.is_ok() {
|
||||
return res;
|
||||
}
|
||||
if matches!(
|
||||
self.hints.get(&DecodeHintType::ALSO_INVERTED),
|
||||
Some(DecodeHintValue::AlsoInverted(true))
|
||||
) {
|
||||
// Calling all readers again with inverted image
|
||||
image.get_black_matrix_mut().flip_self();
|
||||
let res = self.decode_formats(image);
|
||||
if res.is_ok() {
|
||||
return res;
|
||||
}
|
||||
}
|
||||
Err(Exceptions::NOT_FOUND)
|
||||
}
|
||||
|
||||
fn decode_formats<B: Binarizer>(&mut self, image: &mut BinaryBitmap<B>) -> Result<RXingResult> {
|
||||
if !self.possible_formats.is_empty() {
|
||||
let one_d = self.possible_formats.contains(&BarcodeFormat::UPC_A)
|
||||
|| self.possible_formats.contains(&BarcodeFormat::UPC_E)
|
||||
|| self.possible_formats.contains(&BarcodeFormat::EAN_13)
|
||||
|| self.possible_formats.contains(&BarcodeFormat::EAN_8)
|
||||
|| self.possible_formats.contains(&BarcodeFormat::CODABAR)
|
||||
|| self.possible_formats.contains(&BarcodeFormat::CODE_39)
|
||||
|| self.possible_formats.contains(&BarcodeFormat::CODE_93)
|
||||
|| self.possible_formats.contains(&BarcodeFormat::CODE_128)
|
||||
|| self.possible_formats.contains(&BarcodeFormat::ITF)
|
||||
|| self.possible_formats.contains(&BarcodeFormat::RSS_14)
|
||||
|| self.possible_formats.contains(&BarcodeFormat::RSS_EXPANDED);
|
||||
if one_d && !self.try_harder {
|
||||
if let Ok(res) = self.one_d_reader.decode_with_hints(image, &self.hints) {
|
||||
return Ok(res);
|
||||
}
|
||||
}
|
||||
for possible_format in self.possible_formats.iter() {
|
||||
let res = match possible_format {
|
||||
BarcodeFormat::QR_CODE => {
|
||||
QRCodeReader::default().decode_with_hints(image, &self.hints)
|
||||
}
|
||||
BarcodeFormat::DATA_MATRIX => {
|
||||
DataMatrixReader::default().decode_with_hints(image, &self.hints)
|
||||
}
|
||||
BarcodeFormat::AZTEC => {
|
||||
AztecReader::default().decode_with_hints(image, &self.hints)
|
||||
}
|
||||
BarcodeFormat::PDF_417 => {
|
||||
PDF417Reader::default().decode_with_hints(image, &self.hints)
|
||||
}
|
||||
BarcodeFormat::MAXICODE => {
|
||||
MaxiCodeReader::default().decode_with_hints(image, &self.hints)
|
||||
}
|
||||
_ => Err(Exceptions::UNSUPPORTED_OPERATION),
|
||||
};
|
||||
if res.is_ok() {
|
||||
return res;
|
||||
}
|
||||
}
|
||||
if one_d && self.try_harder {
|
||||
if let Ok(res) = self.one_d_reader.decode_with_hints(image, &self.hints) {
|
||||
return Ok(res);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if !self.try_harder {
|
||||
if let Ok(res) = self.one_d_reader.decode_with_hints(image, &self.hints) {
|
||||
return Ok(res);
|
||||
}
|
||||
}
|
||||
|
||||
if let Ok(res) = QRCodeReader::default().decode_with_hints(image, &self.hints) {
|
||||
return Ok(res);
|
||||
}
|
||||
if let Ok(res) = DataMatrixReader::default().decode_with_hints(image, &self.hints) {
|
||||
return Ok(res);
|
||||
}
|
||||
if let Ok(res) = AztecReader::default().decode_with_hints(image, &self.hints) {
|
||||
return Ok(res);
|
||||
}
|
||||
if let Ok(res) = PDF417Reader::default().decode_with_hints(image, &self.hints) {
|
||||
return Ok(res);
|
||||
}
|
||||
if let Ok(res) = MaxiCodeReader::default().decode_with_hints(image, &self.hints) {
|
||||
return Ok(res);
|
||||
}
|
||||
|
||||
if self.try_harder {
|
||||
if let Ok(res) = self.one_d_reader.decode_with_hints(image, &self.hints) {
|
||||
return Ok(res);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Err(Exceptions::UNSUPPORTED_OPERATION)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,7 +49,7 @@ impl Default for CodaBarReader {
|
||||
}
|
||||
|
||||
impl OneDReader for CodaBarReader {
|
||||
fn decodeRow(
|
||||
fn decode_row(
|
||||
&mut self,
|
||||
rowNumber: u32,
|
||||
row: &crate::common::BitArray,
|
||||
@@ -309,7 +309,7 @@ impl CodaBarReader {
|
||||
self.counterLength = 0;
|
||||
// Start from the first white bit.
|
||||
let mut i = row.getNextUnset(0);
|
||||
let end = row.getSize();
|
||||
let end = row.get_size();
|
||||
if i >= end {
|
||||
return Err(Exceptions::NOT_FOUND);
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ use super::{one_d_reader, OneDReader};
|
||||
pub struct Code128Reader;
|
||||
|
||||
impl OneDReader for Code128Reader {
|
||||
fn decodeRow(
|
||||
fn decode_row(
|
||||
&mut self,
|
||||
rowNumber: u32,
|
||||
row: &crate::common::BitArray,
|
||||
@@ -294,7 +294,7 @@ impl OneDReader for Code128Reader {
|
||||
nextStart = row.getNextUnset(nextStart);
|
||||
if !row.isRange(
|
||||
nextStart,
|
||||
row.getSize().min(nextStart + (nextStart - lastStart) / 2),
|
||||
row.get_size().min(nextStart + (nextStart - lastStart) / 2),
|
||||
false,
|
||||
)? {
|
||||
return Err(Exceptions::NOT_FOUND);
|
||||
@@ -354,7 +354,7 @@ impl OneDReader for Code128Reader {
|
||||
}
|
||||
impl Code128Reader {
|
||||
fn findStartPattern(&self, row: &BitArray) -> Result<[usize; 3]> {
|
||||
let width = row.getSize();
|
||||
let width = row.get_size();
|
||||
let rowOffset = row.getNextSet(0);
|
||||
|
||||
let mut counterPosition = 0;
|
||||
@@ -371,7 +371,7 @@ impl Code128Reader {
|
||||
let mut bestVariance = MAX_AVG_VARIANCE;
|
||||
let mut bestMatch = -1_isize;
|
||||
for startCode in CODE_START_A..=CODE_START_C {
|
||||
let variance = one_d_reader::patternMatchVariance(
|
||||
let variance = one_d_reader::pattern_match_variance(
|
||||
&counters,
|
||||
&CODE_PATTERNS[startCode as usize],
|
||||
MAX_INDIVIDUAL_VARIANCE,
|
||||
@@ -410,13 +410,13 @@ impl Code128Reader {
|
||||
}
|
||||
|
||||
fn decodeCode(&self, row: &BitArray, counters: &mut [u32; 6], rowOffset: usize) -> Result<u8> {
|
||||
one_d_reader::recordPattern(row, rowOffset, counters)?;
|
||||
one_d_reader::record_pattern(row, rowOffset, counters)?;
|
||||
let mut bestVariance = MAX_AVG_VARIANCE; // worst variance we'll accept
|
||||
let mut bestMatch = -1_isize;
|
||||
for d in 0..CODE_PATTERNS.len() {
|
||||
let pattern = &CODE_PATTERNS[d];
|
||||
let variance =
|
||||
one_d_reader::patternMatchVariance(counters, pattern, MAX_INDIVIDUAL_VARIANCE);
|
||||
one_d_reader::pattern_match_variance(counters, pattern, MAX_INDIVIDUAL_VARIANCE);
|
||||
if variance < bestVariance {
|
||||
bestVariance = variance;
|
||||
bestMatch = d as isize;
|
||||
|
||||
@@ -483,18 +483,18 @@ fn encode(toEncode: &str, compact: bool, expectedLoopback: &str) -> Result<BitMa
|
||||
WRITER.encode_with_hints(toEncode, &BarcodeFormat::CODE_128, 0, 0, &hints)?;
|
||||
if !expectedLoopback.is_empty() {
|
||||
let row = encRXingResult.getRow(0);
|
||||
let rtRXingResult = reader.decodeRow(0, &row, &HashMap::new())?;
|
||||
let rtRXingResult = reader.decode_row(0, &row, &HashMap::new())?;
|
||||
let actual = rtRXingResult.getText();
|
||||
assert_eq!(expectedLoopback, actual);
|
||||
}
|
||||
if compact {
|
||||
//check that what is encoded compactly yields the same on loopback as what was encoded fast.
|
||||
let row = encRXingResult.getRow(0);
|
||||
let rtRXingResult = reader.decodeRow(0, &row, &HashMap::new())?;
|
||||
let rtRXingResult = reader.decode_row(0, &row, &HashMap::new())?;
|
||||
let actual = rtRXingResult.getText();
|
||||
let encRXingResultFast = WRITER.encode(toEncode, &BarcodeFormat::CODE_128, 0, 0)?;
|
||||
let row = encRXingResultFast.getRow(0);
|
||||
let rtRXingResult = reader.decodeRow(0, &row, &HashMap::new())?;
|
||||
let rtRXingResult = reader.decode_row(0, &row, &HashMap::new())?;
|
||||
assert_eq!(rtRXingResult.getText(), actual);
|
||||
}
|
||||
Ok(encRXingResult)
|
||||
|
||||
@@ -40,7 +40,7 @@ impl Default for Code39Reader {
|
||||
}
|
||||
}
|
||||
impl OneDReader for Code39Reader {
|
||||
fn decodeRow(
|
||||
fn decode_row(
|
||||
&mut self,
|
||||
rowNumber: u32,
|
||||
row: &crate::common::BitArray,
|
||||
@@ -52,12 +52,12 @@ impl OneDReader for Code39Reader {
|
||||
let start = Self::findAsteriskPattern(row, &mut counters)?;
|
||||
// Read off white space
|
||||
let mut nextStart = row.getNextSet(start[1] as usize);
|
||||
let end = row.getSize();
|
||||
let end = row.get_size();
|
||||
|
||||
let mut decodedChar;
|
||||
let mut lastStart;
|
||||
loop {
|
||||
one_d_reader::recordPattern(row, nextStart, &mut counters)?;
|
||||
one_d_reader::record_pattern(row, nextStart, &mut counters)?;
|
||||
let pattern = Self::toNarrowWidePattern(&counters);
|
||||
if pattern < 0 {
|
||||
return Err(Exceptions::NOT_FOUND);
|
||||
@@ -205,7 +205,7 @@ impl Code39Reader {
|
||||
}
|
||||
|
||||
fn findAsteriskPattern(row: &BitArray, counters: &mut [u32]) -> Result<Vec<u32>> {
|
||||
let width = row.getSize();
|
||||
let width = row.get_size();
|
||||
let rowOffset = row.getNextSet(0);
|
||||
|
||||
let mut counterPosition = 0;
|
||||
@@ -429,7 +429,9 @@ mod code_39_extended_mode_test_case {
|
||||
BitMatrix::parse_strings(encodedRXingResult, "1", "0").expect("bitmatrix parse");
|
||||
// let row = BitArray::with_size(matrix.getWidth() as usize);
|
||||
let row = matrix.getRow(0);
|
||||
let result = sut.decodeRow(0, &row, &HashMap::new()).expect("decode row");
|
||||
let result = sut
|
||||
.decode_row(0, &row, &HashMap::new())
|
||||
.expect("decode row");
|
||||
assert_eq!(expectedRXingResult, result.getText());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ impl Default for Code93Reader {
|
||||
}
|
||||
|
||||
impl OneDReader for Code93Reader {
|
||||
fn decodeRow(
|
||||
fn decode_row(
|
||||
&mut self,
|
||||
rowNumber: u32,
|
||||
row: &crate::common::BitArray,
|
||||
@@ -54,7 +54,7 @@ impl OneDReader for Code93Reader {
|
||||
let start = self.findAsteriskPattern(row)?;
|
||||
// Read off white space
|
||||
let mut nextStart = row.getNextSet(start[1]);
|
||||
let end = row.getSize();
|
||||
let end = row.get_size();
|
||||
|
||||
let mut theCounters = self.counters;
|
||||
theCounters.fill(0);
|
||||
@@ -63,7 +63,7 @@ impl OneDReader for Code93Reader {
|
||||
let mut decodedChar;
|
||||
let mut lastStart;
|
||||
loop {
|
||||
one_d_reader::recordPattern(row, nextStart, &mut theCounters)?;
|
||||
one_d_reader::record_pattern(row, nextStart, &mut theCounters)?;
|
||||
let pattern = Self::toPattern(&theCounters);
|
||||
if pattern < 0 {
|
||||
return Err(Exceptions::NOT_FOUND);
|
||||
@@ -163,7 +163,7 @@ impl Code93Reader {
|
||||
}
|
||||
|
||||
fn findAsteriskPattern(&mut self, row: &BitArray) -> Result<[usize; 2]> {
|
||||
let width = row.getSize();
|
||||
let width = row.get_size();
|
||||
let rowOffset = row.getNextSet(0);
|
||||
|
||||
self.counters.fill(0);
|
||||
@@ -385,7 +385,7 @@ mod Code93ReaderTestCase {
|
||||
// let mut row = BitArray::with_size(matrix.getWidth() as usize);
|
||||
let row = matrix.getRow(0);
|
||||
let result = sut
|
||||
.decodeRow(0, &row, &HashMap::new())
|
||||
.decode_row(0, &row, &HashMap::new())
|
||||
.expect("must decode");
|
||||
assert_eq!(expectedRXingResult, result.getText());
|
||||
}
|
||||
|
||||
@@ -50,7 +50,7 @@ impl UPCEANReader for EAN13Reader {
|
||||
// counters[1] = 0;
|
||||
// counters[2] = 0;
|
||||
// counters[3] = 0;
|
||||
let end = row.getSize();
|
||||
let end = row.get_size();
|
||||
let mut rowOffset = startRange[1];
|
||||
|
||||
let mut lgPatternFound = 0;
|
||||
|
||||
@@ -46,7 +46,7 @@ impl UPCEANReader for EAN8Reader {
|
||||
// counters[1] = 0;
|
||||
// counters[2] = 0;
|
||||
// counters[3] = 0;
|
||||
let end = row.getSize();
|
||||
let end = row.get_size();
|
||||
let mut rowOffset = startRange[1];
|
||||
|
||||
let mut x = 0;
|
||||
|
||||
@@ -104,7 +104,7 @@ impl Default for ITFReader {
|
||||
}
|
||||
|
||||
impl OneDReader for ITFReader {
|
||||
fn decodeRow(
|
||||
fn decode_row(
|
||||
&mut self,
|
||||
rowNumber: u32,
|
||||
row: &crate::common::BitArray,
|
||||
@@ -189,7 +189,7 @@ impl ITFReader {
|
||||
|
||||
while payloadStart < payloadEnd {
|
||||
// Get 10 runs of black/white.
|
||||
one_d_reader::recordPattern(row, payloadStart, &mut counterDigitPair)?;
|
||||
one_d_reader::record_pattern(row, payloadStart, &mut counterDigitPair)?;
|
||||
// Split them into each array
|
||||
for k in 0..5 {
|
||||
let twoK = 2 * k;
|
||||
@@ -275,7 +275,7 @@ impl ITFReader {
|
||||
* @throws NotFoundException Throws exception if no black lines are found in the row
|
||||
*/
|
||||
fn skipWhiteSpace(row: &BitArray) -> Result<usize> {
|
||||
let width = row.getSize();
|
||||
let width = row.get_size();
|
||||
let endStart = row.getNextSet(0);
|
||||
if endStart == width {
|
||||
return Err(Exceptions::NOT_FOUND);
|
||||
@@ -312,8 +312,8 @@ impl ITFReader {
|
||||
// Now recalculate the indices of where the 'endblock' starts & stops to
|
||||
// accommodate the reversed nature of the search
|
||||
let temp = endPattern[0];
|
||||
endPattern[0] = row.getSize() - endPattern[1];
|
||||
endPattern[1] = row.getSize() - temp;
|
||||
endPattern[0] = row.get_size() - endPattern[1];
|
||||
endPattern[1] = row.get_size() - temp;
|
||||
|
||||
Ok(endPattern)
|
||||
};
|
||||
@@ -341,7 +341,7 @@ impl ITFReader {
|
||||
) -> Result<[usize; 2]> {
|
||||
let patternLength = pattern.len();
|
||||
let mut counters = vec![0u32; patternLength]; //new int[patternLength];
|
||||
let width = row.getSize();
|
||||
let width = row.get_size();
|
||||
let mut isWhite = false;
|
||||
|
||||
let mut counterPosition = 0;
|
||||
@@ -352,7 +352,7 @@ impl ITFReader {
|
||||
counters[counterPosition] += 1;
|
||||
} else {
|
||||
if counterPosition == patternLength - 1 {
|
||||
if one_d_reader::patternMatchVariance(
|
||||
if one_d_reader::pattern_match_variance(
|
||||
&counters,
|
||||
pattern,
|
||||
MAX_INDIVIDUAL_VARIANCE,
|
||||
@@ -390,7 +390,7 @@ impl ITFReader {
|
||||
let max = PATTERNS.len();
|
||||
for (i, pattern) in PATTERNS.iter().enumerate().take(max) {
|
||||
let variance =
|
||||
one_d_reader::patternMatchVariance(counters, pattern, MAX_INDIVIDUAL_VARIANCE);
|
||||
one_d_reader::pattern_match_variance(counters, pattern, MAX_INDIVIDUAL_VARIANCE);
|
||||
if variance < bestVariance {
|
||||
bestVariance = variance;
|
||||
bestMatch = i as isize;
|
||||
|
||||
@@ -24,25 +24,113 @@ use super::ITFReader;
|
||||
use super::MultiFormatUPCEANReader;
|
||||
use super::OneDReader;
|
||||
use crate::common::Result;
|
||||
use crate::BarcodeFormat;
|
||||
use crate::DecodeHintValue;
|
||||
use crate::Exceptions;
|
||||
use crate::{BarcodeFormat, Binarizer, RXingResult};
|
||||
|
||||
/**
|
||||
* @author dswitkin@google.com (Daniel Switkin)
|
||||
* @author Sean Owen
|
||||
*/
|
||||
#[derive(Default)]
|
||||
pub struct MultiFormatOneDReader(Vec<Box<dyn OneDReader>>);
|
||||
pub struct MultiFormatOneDReader {
|
||||
internal_hints: DecodingHintDictionary,
|
||||
possible_formats: HashSet<BarcodeFormat>,
|
||||
use_code_39_check_digit: bool,
|
||||
rss_14_reader: RSS14Reader,
|
||||
rss_expanded_reader: RSSExpandedReader,
|
||||
}
|
||||
impl OneDReader for MultiFormatOneDReader {
|
||||
fn decodeRow(
|
||||
fn decode_row(
|
||||
&mut self,
|
||||
rowNumber: u32,
|
||||
row_number: u32,
|
||||
row: &crate::common::BitArray,
|
||||
hints: &crate::DecodingHintDictionary,
|
||||
) -> Result<crate::RXingResult> {
|
||||
for reader in self.0.iter_mut() {
|
||||
if let Ok(res) = reader.decodeRow(rowNumber, row, hints) {
|
||||
hints: &DecodingHintDictionary,
|
||||
) -> Result<RXingResult> {
|
||||
let Self {
|
||||
possible_formats,
|
||||
use_code_39_check_digit,
|
||||
internal_hints,
|
||||
rss_14_reader,
|
||||
rss_expanded_reader,
|
||||
} = self;
|
||||
|
||||
if !possible_formats.is_empty() {
|
||||
if possible_formats.contains(&BarcodeFormat::EAN_13)
|
||||
|| possible_formats.contains(&BarcodeFormat::UPC_A)
|
||||
|| possible_formats.contains(&BarcodeFormat::EAN_8)
|
||||
|| possible_formats.contains(&BarcodeFormat::UPC_E)
|
||||
{
|
||||
if let Ok(res) =
|
||||
MultiFormatUPCEANReader::new(internal_hints).decode_row(row_number, row, hints)
|
||||
{
|
||||
return Ok(res);
|
||||
}
|
||||
}
|
||||
if possible_formats.contains(&BarcodeFormat::CODE_39) {
|
||||
if let Ok(res) = Code39Reader::with_use_check_digit(*use_code_39_check_digit)
|
||||
.decode_row(row_number, row, hints)
|
||||
{
|
||||
return Ok(res);
|
||||
}
|
||||
}
|
||||
if possible_formats.contains(&BarcodeFormat::CODE_93) {
|
||||
if let Ok(res) = Code93Reader::default().decode_row(row_number, row, hints) {
|
||||
return Ok(res);
|
||||
}
|
||||
}
|
||||
if possible_formats.contains(&BarcodeFormat::CODE_128) {
|
||||
if let Ok(res) = Code128Reader::default().decode_row(row_number, row, hints) {
|
||||
return Ok(res);
|
||||
}
|
||||
}
|
||||
if possible_formats.contains(&BarcodeFormat::ITF) {
|
||||
if let Ok(res) = ITFReader::default().decode_row(row_number, row, hints) {
|
||||
return Ok(res);
|
||||
}
|
||||
}
|
||||
if possible_formats.contains(&BarcodeFormat::CODABAR) {
|
||||
if let Ok(res) = CodaBarReader::default().decode_row(row_number, row, hints) {
|
||||
return Ok(res);
|
||||
}
|
||||
}
|
||||
if possible_formats.contains(&BarcodeFormat::RSS_14) {
|
||||
if let Ok(res) = rss_14_reader.decode_row(row_number, row, hints) {
|
||||
return Ok(res);
|
||||
}
|
||||
}
|
||||
if possible_formats.contains(&BarcodeFormat::RSS_EXPANDED) {
|
||||
if let Ok(res) = rss_expanded_reader.decode_row(row_number, row, hints) {
|
||||
return Ok(res);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if let Ok(res) =
|
||||
MultiFormatUPCEANReader::new(internal_hints).decode_row(row_number, row, hints)
|
||||
{
|
||||
return Ok(res);
|
||||
}
|
||||
if let Ok(res) = Code39Reader::with_use_check_digit(*use_code_39_check_digit)
|
||||
.decode_row(row_number, row, hints)
|
||||
{
|
||||
return Ok(res);
|
||||
}
|
||||
if let Ok(res) = CodaBarReader::default().decode_row(row_number, row, hints) {
|
||||
return Ok(res);
|
||||
}
|
||||
if let Ok(res) = Code93Reader::default().decode_row(row_number, row, hints) {
|
||||
return Ok(res);
|
||||
}
|
||||
if let Ok(res) = Code128Reader::default().decode_row(row_number, row, hints) {
|
||||
return Ok(res);
|
||||
}
|
||||
if let Ok(res) = ITFReader::default().decode_row(row_number, row, hints) {
|
||||
return Ok(res);
|
||||
}
|
||||
if let Ok(res) = rss_14_reader.decode_row(row_number, row, hints) {
|
||||
return Ok(res);
|
||||
}
|
||||
if let Ok(res) = rss_expanded_reader.decode_row(row_number, row, hints) {
|
||||
return Ok(res);
|
||||
}
|
||||
}
|
||||
@@ -52,57 +140,25 @@ impl OneDReader for MultiFormatOneDReader {
|
||||
}
|
||||
impl MultiFormatOneDReader {
|
||||
pub fn new(hints: &DecodingHintDictionary) -> Self {
|
||||
let useCode39CheckDigit = matches!(
|
||||
let use_code_39_check_digit = matches!(
|
||||
hints.get(&DecodeHintType::ASSUME_CODE_39_CHECK_DIGIT),
|
||||
Some(DecodeHintValue::AssumeCode39CheckDigit(true))
|
||||
);
|
||||
let mut readers: Vec<Box<dyn OneDReader>> = Vec::new();
|
||||
if let Some(DecodeHintValue::PossibleFormats(possibleFormats)) =
|
||||
let possible_formats = if let Some(DecodeHintValue::PossibleFormats(p)) =
|
||||
hints.get(&DecodeHintType::POSSIBLE_FORMATS)
|
||||
{
|
||||
if possibleFormats.contains(&BarcodeFormat::EAN_13)
|
||||
|| possibleFormats.contains(&BarcodeFormat::UPC_A)
|
||||
|| possibleFormats.contains(&BarcodeFormat::EAN_8)
|
||||
|| possibleFormats.contains(&BarcodeFormat::UPC_E)
|
||||
{
|
||||
readers.push(Box::new(MultiFormatUPCEANReader::new(hints)));
|
||||
}
|
||||
if possibleFormats.contains(&BarcodeFormat::CODE_39) {
|
||||
readers.push(Box::new(Code39Reader::with_use_check_digit(
|
||||
useCode39CheckDigit,
|
||||
)));
|
||||
}
|
||||
if possibleFormats.contains(&BarcodeFormat::CODE_93) {
|
||||
readers.push(Box::<Code93Reader>::default());
|
||||
}
|
||||
if possibleFormats.contains(&BarcodeFormat::CODE_128) {
|
||||
readers.push(Box::<Code128Reader>::default());
|
||||
}
|
||||
if possibleFormats.contains(&BarcodeFormat::ITF) {
|
||||
readers.push(Box::<ITFReader>::default());
|
||||
}
|
||||
if possibleFormats.contains(&BarcodeFormat::CODABAR) {
|
||||
readers.push(Box::<CodaBarReader>::default());
|
||||
}
|
||||
if possibleFormats.contains(&BarcodeFormat::RSS_14) {
|
||||
readers.push(Box::<RSS14Reader>::default());
|
||||
}
|
||||
if possibleFormats.contains(&BarcodeFormat::RSS_EXPANDED) {
|
||||
readers.push(Box::<RSSExpandedReader>::default());
|
||||
}
|
||||
}
|
||||
if readers.is_empty() {
|
||||
readers.push(Box::new(MultiFormatUPCEANReader::new(hints)));
|
||||
readers.push(Box::<Code39Reader>::default());
|
||||
readers.push(Box::<CodaBarReader>::default());
|
||||
readers.push(Box::<Code93Reader>::default());
|
||||
readers.push(Box::<Code128Reader>::default());
|
||||
readers.push(Box::<ITFReader>::default());
|
||||
readers.push(Box::<RSS14Reader>::default());
|
||||
readers.push(Box::<RSSExpandedReader>::default());
|
||||
}
|
||||
p.clone()
|
||||
} else {
|
||||
HashSet::new()
|
||||
};
|
||||
|
||||
Self(readers)
|
||||
Self {
|
||||
possible_formats,
|
||||
use_code_39_check_digit,
|
||||
rss_14_reader: RSS14Reader::default(),
|
||||
internal_hints: hints.clone(),
|
||||
rss_expanded_reader: RSSExpandedReader::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -111,20 +167,20 @@ use crate::DecodingHintDictionary;
|
||||
use crate::RXingResultMetadataType;
|
||||
use crate::RXingResultMetadataValue;
|
||||
use crate::Reader;
|
||||
use std::collections::HashMap;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
|
||||
impl Reader for MultiFormatOneDReader {
|
||||
fn decode(&mut self, image: &mut crate::BinaryBitmap) -> Result<crate::RXingResult> {
|
||||
fn decode<B: Binarizer>(&mut self, image: &mut crate::BinaryBitmap<B>) -> Result<RXingResult> {
|
||||
self.decode_with_hints(image, &HashMap::new())
|
||||
}
|
||||
|
||||
// Note that we don't try rotation without the try harder flag, even if rotation was supported.
|
||||
fn decode_with_hints(
|
||||
fn decode_with_hints<B: Binarizer>(
|
||||
&mut self,
|
||||
image: &mut crate::BinaryBitmap,
|
||||
image: &mut crate::BinaryBitmap<B>,
|
||||
hints: &DecodingHintDictionary,
|
||||
) -> Result<crate::RXingResult> {
|
||||
let first_try = self.doDecode(image, hints);
|
||||
) -> Result<RXingResult> {
|
||||
let first_try = self._do_decode(image, hints);
|
||||
if first_try.is_ok() {
|
||||
return first_try;
|
||||
}
|
||||
@@ -133,9 +189,9 @@ impl Reader for MultiFormatOneDReader {
|
||||
hints.get(&DecodeHintType::TRY_HARDER),
|
||||
Some(DecodeHintValue::TryHarder(true))
|
||||
);
|
||||
if tryHarder && image.isRotateSupported() {
|
||||
let mut rotatedImage = image.rotateCounterClockwise();
|
||||
let mut result = self.doDecode(&mut rotatedImage, hints)?;
|
||||
if tryHarder && image.is_rotate_supported() {
|
||||
let mut rotatedImage = image.rotate_counter_clockwise();
|
||||
let mut result = self._do_decode(&mut rotatedImage, hints)?;
|
||||
// Record that we found it rotated 90 degrees CCW / 270 degrees CW
|
||||
let metadata = result.getRXingResultMetadata();
|
||||
let mut orientation = 270;
|
||||
@@ -156,7 +212,7 @@ impl Reader for MultiFormatOneDReader {
|
||||
RXingResultMetadataValue::Orientation(orientation),
|
||||
);
|
||||
// Update result points
|
||||
let height = rotatedImage.getHeight();
|
||||
let height = rotatedImage.get_height();
|
||||
let total_points = result.getPoints().len();
|
||||
let points = result.getPointsMut();
|
||||
for point in points.iter_mut().take(total_points) {
|
||||
@@ -171,8 +227,7 @@ impl Reader for MultiFormatOneDReader {
|
||||
}
|
||||
|
||||
fn reset(&mut self) {
|
||||
for reader in self.0.iter_mut() {
|
||||
reader.reset();
|
||||
}
|
||||
self.rss_14_reader.reset();
|
||||
self.rss_expanded_reader.reset();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,11 +15,11 @@
|
||||
*/
|
||||
|
||||
use crate::common::Result;
|
||||
use crate::BarcodeFormat;
|
||||
use crate::DecodeHintValue;
|
||||
use crate::Exceptions;
|
||||
use crate::RXingResult;
|
||||
use crate::Reader;
|
||||
use crate::{BarcodeFormat, Binarizer};
|
||||
|
||||
use super::EAN13Reader;
|
||||
use super::EAN8Reader;
|
||||
@@ -35,47 +35,122 @@ use super::{OneDReader, UPCEANReader};
|
||||
*
|
||||
* @author Sean Owen
|
||||
*/
|
||||
pub struct MultiFormatUPCEANReader(Vec<Box<dyn UPCEANReader>>);
|
||||
pub struct MultiFormatUPCEANReader {
|
||||
possible_formats: HashSet<BarcodeFormat>,
|
||||
}
|
||||
|
||||
impl OneDReader for MultiFormatUPCEANReader {
|
||||
fn decode_row(
|
||||
&mut self,
|
||||
rowNumber: u32,
|
||||
row: &crate::common::BitArray,
|
||||
hints: &DecodingHintDictionary,
|
||||
) -> Result<RXingResult> {
|
||||
let Self {
|
||||
ref possible_formats,
|
||||
} = self;
|
||||
// Compute this location once and reuse it on multiple implementations
|
||||
let start_guard_pattern = STAND_IN.find_start_guard_pattern(row)?;
|
||||
|
||||
if !possible_formats.is_empty() {
|
||||
if possible_formats.contains(&BarcodeFormat::EAN_13) {
|
||||
if let Ok(res) = self.try_decode_function(
|
||||
&EAN13Reader::default(),
|
||||
rowNumber,
|
||||
row,
|
||||
hints,
|
||||
&start_guard_pattern,
|
||||
) {
|
||||
return Ok(res);
|
||||
}
|
||||
} else if possible_formats.contains(&BarcodeFormat::UPC_A) {
|
||||
if let Ok(res) = self.try_decode_function(
|
||||
&UPCAReader::default(),
|
||||
rowNumber,
|
||||
row,
|
||||
hints,
|
||||
&start_guard_pattern,
|
||||
) {
|
||||
return Ok(res);
|
||||
}
|
||||
}
|
||||
if possible_formats.contains(&BarcodeFormat::EAN_8) {
|
||||
if let Ok(res) = self.try_decode_function(
|
||||
&EAN8Reader::default(),
|
||||
rowNumber,
|
||||
row,
|
||||
hints,
|
||||
&start_guard_pattern,
|
||||
) {
|
||||
return Ok(res);
|
||||
}
|
||||
}
|
||||
if possible_formats.contains(&BarcodeFormat::UPC_E) {
|
||||
if let Ok(res) = self.try_decode_function(
|
||||
&UPCEReader::default(),
|
||||
rowNumber,
|
||||
row,
|
||||
hints,
|
||||
&start_guard_pattern,
|
||||
) {
|
||||
return Ok(res);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if let Ok(res) = self.try_decode_function(
|
||||
&EAN13Reader::default(),
|
||||
rowNumber,
|
||||
row,
|
||||
hints,
|
||||
&start_guard_pattern,
|
||||
) {
|
||||
return Ok(res);
|
||||
}
|
||||
if let Ok(res) = self.try_decode_function(
|
||||
&EAN8Reader::default(),
|
||||
rowNumber,
|
||||
row,
|
||||
hints,
|
||||
&start_guard_pattern,
|
||||
) {
|
||||
return Ok(res);
|
||||
}
|
||||
if let Ok(res) = self.try_decode_function(
|
||||
&UPCEReader::default(),
|
||||
rowNumber,
|
||||
row,
|
||||
hints,
|
||||
&start_guard_pattern,
|
||||
) {
|
||||
return Ok(res);
|
||||
}
|
||||
}
|
||||
|
||||
Err(Exceptions::NOT_FOUND)
|
||||
}
|
||||
}
|
||||
|
||||
impl MultiFormatUPCEANReader {
|
||||
pub fn new(hints: &DecodingHintDictionary) -> Self {
|
||||
let mut readers: Vec<Box<dyn UPCEANReader>> = Vec::new();
|
||||
if let Some(DecodeHintValue::PossibleFormats(possibleFormats)) =
|
||||
let possible_formats = if let Some(DecodeHintValue::PossibleFormats(p)) =
|
||||
hints.get(&DecodeHintType::POSSIBLE_FORMATS)
|
||||
{
|
||||
// Collection<BarcodeFormat> possibleFormats = hints == null ? null :
|
||||
// (Collection<BarcodeFormat>) hints.get(DecodeHintType.POSSIBLE_FORMATS);
|
||||
// Collection<UPCEANReader> readers = new ArrayList<>();
|
||||
if possibleFormats.contains(&BarcodeFormat::EAN_13) {
|
||||
readers.push(Box::<EAN13Reader>::default());
|
||||
} else if possibleFormats.contains(&BarcodeFormat::UPC_A) {
|
||||
readers.push(Box::<UPCAReader>::default());
|
||||
}
|
||||
if possibleFormats.contains(&BarcodeFormat::EAN_8) {
|
||||
readers.push(Box::<EAN8Reader>::default());
|
||||
}
|
||||
if possibleFormats.contains(&BarcodeFormat::UPC_E) {
|
||||
readers.push(Box::<UPCEReader>::default());
|
||||
}
|
||||
}
|
||||
if readers.is_empty() {
|
||||
readers.push(Box::<EAN13Reader>::default());
|
||||
// UPC-A is covered by EAN-13
|
||||
readers.push(Box::<EAN8Reader>::default());
|
||||
readers.push(Box::<UPCEReader>::default());
|
||||
}
|
||||
p.clone()
|
||||
} else {
|
||||
HashSet::default()
|
||||
};
|
||||
|
||||
Self(readers)
|
||||
Self { possible_formats }
|
||||
}
|
||||
|
||||
fn try_decode_function(
|
||||
fn try_decode_function<R: UPCEANReader>(
|
||||
&self,
|
||||
reader: &Box<dyn UPCEANReader>,
|
||||
reader: &R,
|
||||
rowNumber: u32,
|
||||
row: &crate::common::BitArray,
|
||||
hints: &crate::DecodingHintDictionary,
|
||||
hints: &DecodingHintDictionary,
|
||||
startGuardPattern: &[usize; 2],
|
||||
) -> Result<crate::RXingResult> {
|
||||
) -> Result<RXingResult> {
|
||||
let result = reader.decodeRowWithGuardRange(rowNumber, row, startGuardPattern, hints)?;
|
||||
// Special case: a 12-digit code encoded in UPC-A is identical to a "0"
|
||||
// followed by those 12 digits encoded as EAN-13. Each will recognize such a code,
|
||||
@@ -117,46 +192,24 @@ impl MultiFormatUPCEANReader {
|
||||
}
|
||||
}
|
||||
|
||||
impl OneDReader for MultiFormatUPCEANReader {
|
||||
fn decodeRow(
|
||||
&mut self,
|
||||
rowNumber: u32,
|
||||
row: &crate::common::BitArray,
|
||||
hints: &crate::DecodingHintDictionary,
|
||||
) -> Result<crate::RXingResult> {
|
||||
// Compute this location once and reuse it on multiple implementations
|
||||
let startGuardPattern = STAND_IN.findStartGuardPattern(row)?;
|
||||
for reader in &self.0 {
|
||||
// for (UPCEANReader reader : readers) {
|
||||
let try_result =
|
||||
self.try_decode_function(reader, rowNumber, row, hints, &startGuardPattern);
|
||||
if try_result.is_ok() {
|
||||
return try_result;
|
||||
}
|
||||
}
|
||||
|
||||
Err(Exceptions::NOT_FOUND)
|
||||
}
|
||||
}
|
||||
|
||||
use crate::DecodeHintType;
|
||||
use crate::DecodingHintDictionary;
|
||||
use crate::RXingResultMetadataType;
|
||||
use crate::RXingResultMetadataValue;
|
||||
use std::collections::HashMap;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
|
||||
impl Reader for MultiFormatUPCEANReader {
|
||||
fn decode(&mut self, image: &mut crate::BinaryBitmap) -> Result<crate::RXingResult> {
|
||||
fn decode<B: Binarizer>(&mut self, image: &mut crate::BinaryBitmap<B>) -> Result<RXingResult> {
|
||||
self.decode_with_hints(image, &HashMap::new())
|
||||
}
|
||||
|
||||
// Note that we don't try rotation without the try harder flag, even if rotation was supported.
|
||||
fn decode_with_hints(
|
||||
fn decode_with_hints<B: Binarizer>(
|
||||
&mut self,
|
||||
image: &mut crate::BinaryBitmap,
|
||||
image: &mut crate::BinaryBitmap<B>,
|
||||
hints: &DecodingHintDictionary,
|
||||
) -> Result<crate::RXingResult> {
|
||||
let first_try = self.doDecode(image, hints);
|
||||
) -> Result<RXingResult> {
|
||||
let first_try = self._do_decode(image, hints);
|
||||
if first_try.is_ok() {
|
||||
return first_try;
|
||||
}
|
||||
@@ -165,16 +218,16 @@ impl Reader for MultiFormatUPCEANReader {
|
||||
hints.get(&DecodeHintType::TRY_HARDER),
|
||||
Some(DecodeHintValue::TryHarder(true))
|
||||
);
|
||||
if tryHarder && image.isRotateSupported() {
|
||||
let mut rotatedImage = image.rotateCounterClockwise();
|
||||
let mut result = self.doDecode(&mut rotatedImage, hints)?;
|
||||
if tryHarder && image.is_rotate_supported() {
|
||||
let mut rotatedImage = image.rotate_counter_clockwise();
|
||||
let mut result = self._do_decode(&mut rotatedImage, hints)?;
|
||||
// Record that we found it rotated 90 degrees CCW / 270 degrees CW
|
||||
let metadata = result.getRXingResultMetadata();
|
||||
let mut orientation = 270;
|
||||
if metadata.contains_key(&RXingResultMetadataType::ORIENTATION) {
|
||||
// But if we found it reversed in doDecode(), add in that result here:
|
||||
orientation = (orientation
|
||||
+ if let Some(crate::RXingResultMetadataValue::Orientation(or)) =
|
||||
+ if let Some(RXingResultMetadataValue::Orientation(or)) =
|
||||
metadata.get(&RXingResultMetadataType::ORIENTATION)
|
||||
{
|
||||
*or
|
||||
@@ -188,7 +241,7 @@ impl Reader for MultiFormatUPCEANReader {
|
||||
RXingResultMetadataValue::Orientation(orientation),
|
||||
);
|
||||
// Update result points
|
||||
let height = rotatedImage.getHeight();
|
||||
let height = rotatedImage.get_height();
|
||||
let total_points = result.getPoints().len();
|
||||
let points = result.getPointsMut();
|
||||
for point in points.iter_mut().take(total_points) {
|
||||
@@ -201,10 +254,4 @@ impl Reader for MultiFormatUPCEANReader {
|
||||
Err(Exceptions::NOT_FOUND)
|
||||
}
|
||||
}
|
||||
|
||||
fn reset(&mut self) {
|
||||
for reader in self.0.iter_mut() {
|
||||
reader.reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,8 +16,8 @@
|
||||
|
||||
use crate::{
|
||||
common::{BitArray, Result},
|
||||
point, BinaryBitmap, DecodeHintType, DecodeHintValue, DecodingHintDictionary, Exceptions,
|
||||
RXingResult, RXingResultMetadataType, RXingResultMetadataValue, Reader,
|
||||
point, Binarizer, BinaryBitmap, DecodeHintType, DecodeHintValue, DecodingHintDictionary,
|
||||
Exceptions, RXingResult, RXingResultMetadataType, RXingResultMetadataValue, Reader,
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -42,45 +42,45 @@ pub trait OneDReader: Reader {
|
||||
* @return The contents of the decoded barcode
|
||||
* @throws NotFoundException Any spontaneous errors which occur
|
||||
*/
|
||||
fn doDecode(
|
||||
fn _do_decode<B: Binarizer>(
|
||||
&mut self,
|
||||
image: &mut BinaryBitmap,
|
||||
image: &mut BinaryBitmap<B>,
|
||||
hints: &DecodingHintDictionary,
|
||||
) -> Result<RXingResult> {
|
||||
let mut hints = hints.clone();
|
||||
let width = image.getWidth();
|
||||
let height = image.getHeight();
|
||||
let width = image.get_width();
|
||||
let height = image.get_height();
|
||||
|
||||
let tryHarder = matches!(
|
||||
let try_harder = matches!(
|
||||
hints.get(&DecodeHintType::TRY_HARDER),
|
||||
Some(DecodeHintValue::TryHarder(true))
|
||||
);
|
||||
let rowStep = 1.max(height >> (if tryHarder { 8 } else { 5 }));
|
||||
let maxLines = if tryHarder {
|
||||
let row_step = 1.max(height >> (if try_harder { 8 } else { 5 }));
|
||||
let max_lines = if try_harder {
|
||||
height // Look at the whole image, not just the center
|
||||
} else {
|
||||
15 // 15 rows spaced 1/32 apart is roughly the middle half of the image
|
||||
};
|
||||
|
||||
let middle = height / 2;
|
||||
for x in 0..maxLines {
|
||||
for x in 0..max_lines {
|
||||
// Scanning from the middle out. Determine which row we're looking at next:
|
||||
let rowStepsAboveOrBelow = (x + 1) / 2;
|
||||
let isAbove = (x & 0x01) == 0; // i.e. is x even?
|
||||
let rowNumber: isize = middle as isize
|
||||
+ rowStep as isize
|
||||
* (if isAbove {
|
||||
rowStepsAboveOrBelow as isize
|
||||
let row_steps_above_or_below = (x + 1) / 2;
|
||||
let is_above = (x & 0x01) == 0; // i.e. is x even?
|
||||
let row_number: isize = middle as isize
|
||||
+ row_step as isize
|
||||
* (if is_above {
|
||||
row_steps_above_or_below as isize
|
||||
} else {
|
||||
-(rowStepsAboveOrBelow as isize)
|
||||
-(row_steps_above_or_below as isize)
|
||||
});
|
||||
if rowNumber < 0 || rowNumber >= height as isize {
|
||||
if row_number < 0 || row_number >= height as isize {
|
||||
// Oops, if we run off the top or bottom, stop
|
||||
break;
|
||||
}
|
||||
|
||||
// Estimate black point for this row and load it:
|
||||
let mut row = if let Ok(res) = image.getBlackRow(rowNumber as usize) {
|
||||
let mut row = if let Ok(res) = image.get_black_row(row_number as usize) {
|
||||
res
|
||||
} else {
|
||||
continue;
|
||||
@@ -104,9 +104,9 @@ pub trait OneDReader: Reader {
|
||||
hints.remove(&DecodeHintType::NEED_RESULT_POINT_CALLBACK);
|
||||
}
|
||||
}
|
||||
let Ok(mut result) = self.decodeRow(rowNumber as u32, &row, &hints) else {
|
||||
continue
|
||||
};
|
||||
let Ok(mut result) = self.decode_row(row_number as u32, &row, &hints) else {
|
||||
continue
|
||||
};
|
||||
// We found our barcode
|
||||
if attempt == 1 {
|
||||
// But it was upside down, so note that
|
||||
@@ -140,7 +140,7 @@ pub trait OneDReader: Reader {
|
||||
* @throws ChecksumException if a potential barcode is found but does not pass its checksum
|
||||
* @throws FormatException if a potential barcode is found but format is invalid
|
||||
*/
|
||||
fn decodeRow(
|
||||
fn decode_row(
|
||||
&mut self,
|
||||
rowNumber: u32,
|
||||
row: &BitArray,
|
||||
@@ -158,39 +158,42 @@ pub trait OneDReader: Reader {
|
||||
* @param maxIndividualVariance The most any counter can differ before we give up
|
||||
* @return ratio of total variance between counters and pattern compared to total pattern size
|
||||
*/
|
||||
pub fn patternMatchVariance(counters: &[u32], pattern: &[u32], maxIndividualVariance: f32) -> f32 {
|
||||
let mut maxIndividualVariance = maxIndividualVariance;
|
||||
let numCounters = counters.len();
|
||||
pub fn pattern_match_variance(
|
||||
counters: &[u32],
|
||||
pattern: &[u32],
|
||||
mut max_individual_variance: f32,
|
||||
) -> f32 {
|
||||
let num_counters = counters.len();
|
||||
let mut total = 0.0;
|
||||
let mut patternLength = 0;
|
||||
for i in 0..numCounters {
|
||||
let mut pattern_length = 0;
|
||||
for i in 0..num_counters {
|
||||
total += counters[i] as f32;
|
||||
patternLength += pattern[i];
|
||||
pattern_length += pattern[i];
|
||||
}
|
||||
if total < patternLength as f32 {
|
||||
if total < pattern_length as f32 {
|
||||
// If we don't even have one pixel per unit of bar width, assume this is too small
|
||||
// to reliably match, so fail:
|
||||
return f32::INFINITY;
|
||||
}
|
||||
|
||||
let unitBarWidth = total / patternLength as f32;
|
||||
maxIndividualVariance *= unitBarWidth;
|
||||
let unit_bar_width = total / pattern_length as f32;
|
||||
max_individual_variance *= unit_bar_width;
|
||||
|
||||
let mut totalVariance = 0.0;
|
||||
for x in 0..numCounters {
|
||||
let mut total_variance = 0.0;
|
||||
for x in 0..num_counters {
|
||||
let counter = counters[x];
|
||||
let scaledPattern = (pattern[x] as f32) * unitBarWidth;
|
||||
let variance = if (counter as f32) > scaledPattern {
|
||||
counter as f32 - scaledPattern
|
||||
let scaled_pattern = (pattern[x] as f32) * unit_bar_width;
|
||||
let variance = if (counter as f32) > scaled_pattern {
|
||||
counter as f32 - scaled_pattern
|
||||
} else {
|
||||
scaledPattern - counter as f32
|
||||
scaled_pattern - counter as f32
|
||||
};
|
||||
if variance > maxIndividualVariance {
|
||||
if variance > max_individual_variance {
|
||||
return f32::INFINITY;
|
||||
}
|
||||
totalVariance += variance;
|
||||
total_variance += variance;
|
||||
}
|
||||
totalVariance / total
|
||||
total_variance / total
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -206,56 +209,56 @@ pub fn patternMatchVariance(counters: &[u32], pattern: &[u32], maxIndividualVari
|
||||
* @throws NotFoundException if counters cannot be filled entirely from row before running out
|
||||
* of pixels
|
||||
*/
|
||||
pub fn recordPattern(row: &BitArray, start: usize, counters: &mut [u32]) -> Result<()> {
|
||||
let numCounters = counters.len();
|
||||
pub fn record_pattern(row: &BitArray, start: usize, counters: &mut [u32]) -> Result<()> {
|
||||
let num_counters = counters.len();
|
||||
counters.fill(0);
|
||||
|
||||
let end = row.getSize();
|
||||
let end = row.get_size();
|
||||
if start >= end {
|
||||
return Err(Exceptions::NOT_FOUND);
|
||||
}
|
||||
|
||||
let mut isWhite = !row.get(start);
|
||||
let mut counterPosition = 0;
|
||||
let mut is_white = !row.get(start);
|
||||
let mut counter_position = 0;
|
||||
let mut i = start;
|
||||
while i < end {
|
||||
if row.get(i) != isWhite {
|
||||
counters[counterPosition] += 1;
|
||||
if row.get(i) != is_white {
|
||||
counters[counter_position] += 1;
|
||||
} else {
|
||||
counterPosition += 1;
|
||||
if counterPosition == numCounters {
|
||||
counter_position += 1;
|
||||
if counter_position == num_counters {
|
||||
break;
|
||||
} else {
|
||||
counters[counterPosition] = 1;
|
||||
isWhite = !isWhite;
|
||||
counters[counter_position] = 1;
|
||||
is_white = !is_white;
|
||||
}
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
// If we read fully the last section of pixels and filled up our counters -- or filled
|
||||
// the last counter but ran off the side of the image, OK. Otherwise, a problem.
|
||||
if !(counterPosition == numCounters || (counterPosition == numCounters - 1 && i == end)) {
|
||||
if !(counter_position == num_counters || (counter_position == num_counters - 1 && i == end)) {
|
||||
return Err(Exceptions::NOT_FOUND);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn recordPatternInReverse(row: &BitArray, start: usize, counters: &mut [u32]) -> Result<()> {
|
||||
pub fn record_pattern_in_reverse(row: &BitArray, start: usize, counters: &mut [u32]) -> Result<()> {
|
||||
let mut start = start;
|
||||
// This could be more efficient I guess
|
||||
let mut numTransitionsLeft = counters.len() as isize;
|
||||
let mut num_transitions_left = counters.len() as isize;
|
||||
let mut last = row.get(start);
|
||||
while start > 0 && numTransitionsLeft >= 0 {
|
||||
while start > 0 && num_transitions_left >= 0 {
|
||||
start -= 1;
|
||||
if row.get(start) != last {
|
||||
numTransitionsLeft -= 1;
|
||||
num_transitions_left -= 1;
|
||||
last = !last;
|
||||
}
|
||||
}
|
||||
if numTransitionsLeft >= 0 {
|
||||
if num_transitions_left >= 0 {
|
||||
return Err(Exceptions::NOT_FOUND);
|
||||
}
|
||||
recordPattern(row, start + 1, counters)?;
|
||||
record_pattern(row, start + 1, counters)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -33,8 +33,11 @@ pub trait AbstractRSSReaderTrait: OneDReader {
|
||||
|
||||
fn parseFinderValue(counters: &[u32], finderPatterns: &[[u32; 4]]) -> Result<u32> {
|
||||
for (value, pattern) in finderPatterns.iter().enumerate() {
|
||||
if one_d_reader::patternMatchVariance(counters, pattern, Self::MAX_INDIVIDUAL_VARIANCE)
|
||||
< Self::MAX_AVG_VARIANCE
|
||||
if one_d_reader::pattern_match_variance(
|
||||
counters,
|
||||
pattern,
|
||||
Self::MAX_INDIVIDUAL_VARIANCE,
|
||||
) < Self::MAX_AVG_VARIANCE
|
||||
{
|
||||
return Ok(value as u32);
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ pub struct AI01392xDecoder<'a> {
|
||||
impl AI01decoder for AI01392xDecoder<'_> {}
|
||||
impl AbstractExpandedDecoder for AI01392xDecoder<'_> {
|
||||
fn parseInformation(&mut self) -> Result<String> {
|
||||
if self.information.getSize() < Self::HEADER_SIZE + Self::GTIN_SIZE as usize {
|
||||
if self.information.get_size() < Self::HEADER_SIZE + Self::GTIN_SIZE as usize {
|
||||
return Err(crate::Exceptions::NOT_FOUND);
|
||||
}
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ pub struct AI01393xDecoder<'a> {
|
||||
impl AI01decoder for AI01393xDecoder<'_> {}
|
||||
impl AbstractExpandedDecoder for AI01393xDecoder<'_> {
|
||||
fn parseInformation(&mut self) -> Result<String> {
|
||||
if self.information.getSize() < Self::HEADER_SIZE + Self::GTIN_SIZE as usize {
|
||||
if self.information.get_size() < Self::HEADER_SIZE + Self::GTIN_SIZE as usize {
|
||||
return Err(crate::Exceptions::NOT_FOUND);
|
||||
}
|
||||
|
||||
|
||||
@@ -54,7 +54,7 @@ impl AI01weightDecoder for AI013x0x1xDecoder<'_> {
|
||||
impl AI01decoder for AI013x0x1xDecoder<'_> {}
|
||||
impl AbstractExpandedDecoder for AI013x0x1xDecoder<'_> {
|
||||
fn parseInformation(&mut self) -> Result<String> {
|
||||
if self.information.getSize()
|
||||
if self.information.get_size()
|
||||
!= Self::HEADER_SIZE + Self::GTIN_SIZE as usize + Self::WEIGHT_SIZE + Self::DATE_SIZE
|
||||
{
|
||||
return Err(crate::Exceptions::NOT_FOUND);
|
||||
|
||||
@@ -50,7 +50,7 @@ impl AI01weightDecoder for AI013x0xDecoder<'_> {
|
||||
}
|
||||
impl AbstractExpandedDecoder for AI013x0xDecoder<'_> {
|
||||
fn parseInformation(&mut self) -> Result<String> {
|
||||
if self.information.getSize()
|
||||
if self.information.get_size()
|
||||
!= Self::HEADER_SIZE + Self::GTIN_SIZE as usize + Self::WEIGHT_SIZE
|
||||
{
|
||||
return Err(crate::Exceptions::NOT_FOUND);
|
||||
|
||||
@@ -82,8 +82,8 @@ impl<'a> GeneralAppIdDecoder<'_> {
|
||||
fn isStillNumeric(&self, pos: usize) -> bool {
|
||||
// It's numeric if it still has 7 positions
|
||||
// and one of the first 4 bits is "1".
|
||||
if pos + 7 > self.information.getSize() {
|
||||
return pos + 4 <= self.information.getSize();
|
||||
if pos + 7 > self.information.get_size() {
|
||||
return pos + 4 <= self.information.get_size();
|
||||
}
|
||||
|
||||
for i in pos..pos + 3 {
|
||||
@@ -97,17 +97,17 @@ impl<'a> GeneralAppIdDecoder<'_> {
|
||||
}
|
||||
|
||||
fn decodeNumeric(&self, pos: usize) -> Result<DecodedNumeric> {
|
||||
if pos + 7 > self.information.getSize() {
|
||||
if pos + 7 > self.information.get_size() {
|
||||
let numeric = self.extractNumericValueFromBitArray(pos, 4);
|
||||
if numeric == 0 {
|
||||
return DecodedNumeric::new(
|
||||
self.information.getSize(),
|
||||
self.information.get_size(),
|
||||
DecodedNumeric::FNC1,
|
||||
DecodedNumeric::FNC1,
|
||||
);
|
||||
}
|
||||
return DecodedNumeric::new(
|
||||
self.information.getSize(),
|
||||
self.information.get_size(),
|
||||
numeric - 1,
|
||||
DecodedNumeric::FNC1,
|
||||
);
|
||||
@@ -263,10 +263,10 @@ impl<'a> GeneralAppIdDecoder<'_> {
|
||||
self.current.incrementPosition(3);
|
||||
self.current.setNumeric();
|
||||
} else if self.isAlphaTo646ToAlphaLatch(self.current.getPosition()) {
|
||||
if self.current.getPosition() + 5 < self.information.getSize() {
|
||||
if self.current.getPosition() + 5 < self.information.get_size() {
|
||||
self.current.incrementPosition(5);
|
||||
} else {
|
||||
self.current.setPosition(self.information.getSize());
|
||||
self.current.setPosition(self.information.get_size());
|
||||
}
|
||||
|
||||
self.current.setAlpha();
|
||||
@@ -295,10 +295,10 @@ impl<'a> GeneralAppIdDecoder<'_> {
|
||||
self.current.incrementPosition(3);
|
||||
self.current.setNumeric();
|
||||
} else if self.isAlphaTo646ToAlphaLatch(self.current.getPosition()) {
|
||||
if self.current.getPosition() + 5 < self.information.getSize() {
|
||||
if self.current.getPosition() + 5 < self.information.get_size() {
|
||||
self.current.incrementPosition(5);
|
||||
} else {
|
||||
self.current.setPosition(self.information.getSize());
|
||||
self.current.setPosition(self.information.get_size());
|
||||
}
|
||||
|
||||
self.current.setIsoIec646();
|
||||
@@ -308,7 +308,7 @@ impl<'a> GeneralAppIdDecoder<'_> {
|
||||
}
|
||||
|
||||
fn isStillIsoIec646(&self, pos: usize) -> bool {
|
||||
if pos + 5 > self.information.getSize() {
|
||||
if pos + 5 > self.information.get_size() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -317,7 +317,7 @@ impl<'a> GeneralAppIdDecoder<'_> {
|
||||
return true;
|
||||
}
|
||||
|
||||
if pos + 7 > self.information.getSize() {
|
||||
if pos + 7 > self.information.get_size() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -326,7 +326,7 @@ impl<'a> GeneralAppIdDecoder<'_> {
|
||||
return true;
|
||||
}
|
||||
|
||||
if pos + 8 > self.information.getSize() {
|
||||
if pos + 8 > self.information.get_size() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -394,7 +394,7 @@ impl<'a> GeneralAppIdDecoder<'_> {
|
||||
}
|
||||
|
||||
fn isStillAlpha(&self, pos: usize) -> bool {
|
||||
if pos + 5 > self.information.getSize() {
|
||||
if pos + 5 > self.information.get_size() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -404,7 +404,7 @@ impl<'a> GeneralAppIdDecoder<'_> {
|
||||
return true;
|
||||
}
|
||||
|
||||
if pos + 6 > self.information.getSize() {
|
||||
if pos + 6 > self.information.get_size() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -452,12 +452,12 @@ impl<'a> GeneralAppIdDecoder<'_> {
|
||||
}
|
||||
|
||||
fn isAlphaTo646ToAlphaLatch(&self, pos: usize) -> bool {
|
||||
if pos + 1 > self.information.getSize() {
|
||||
if pos + 1 > self.information.get_size() {
|
||||
return false;
|
||||
}
|
||||
|
||||
let mut i = 0;
|
||||
while i < 5 && i + pos < self.information.getSize() {
|
||||
while i < 5 && i + pos < self.information.get_size() {
|
||||
if i == 2 {
|
||||
if !self.information.get(pos + 2) {
|
||||
return false;
|
||||
@@ -474,7 +474,7 @@ impl<'a> GeneralAppIdDecoder<'_> {
|
||||
|
||||
fn isAlphaOr646ToNumericLatch(&self, pos: usize) -> bool {
|
||||
// Next is alphanumeric if there are 3 positions and they are all zeros
|
||||
if pos + 3 > self.information.getSize() {
|
||||
if pos + 3 > self.information.get_size() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -490,12 +490,12 @@ impl<'a> GeneralAppIdDecoder<'_> {
|
||||
fn isNumericToAlphaNumericLatch(&self, pos: usize) -> bool {
|
||||
// Next is alphanumeric if there are 4 positions and they are all zeros, or
|
||||
// if there is a subset of this just before the end of the symbol
|
||||
if pos + 1 > self.information.getSize() {
|
||||
if pos + 1 > self.information.get_size() {
|
||||
return false;
|
||||
}
|
||||
|
||||
let mut i = 0;
|
||||
while i < 4 && i + pos < self.information.getSize() {
|
||||
while i < 4 && i + pos < self.information.get_size() {
|
||||
if self.information.get(pos + i) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ mod rss_expanded_internal_test_case;
|
||||
|
||||
#[cfg(test)]
|
||||
#[cfg(feature = "image")]
|
||||
mod rss_expanded_image_2_binary_test_tase;
|
||||
mod rss_expanded_image_2_binary_test_case;
|
||||
|
||||
#[cfg(test)]
|
||||
#[cfg(feature = "image")]
|
||||
|
||||
@@ -24,8 +24,6 @@
|
||||
* http://www.piramidepse.com/
|
||||
*/
|
||||
|
||||
use std::rc::Rc;
|
||||
|
||||
/**
|
||||
* @author Pablo Orduña, University of Deusto (pablo.orduna@deusto.es)
|
||||
* @author Eduardo Castillejo, University of Deusto (eduardo.castillejo@deusto.es)
|
||||
@@ -174,11 +172,11 @@ fn assertCorrectImage2binary(fileName: &str, expected: &str) {
|
||||
let path = format!("test_resources/blackbox/rssexpanded-1/{fileName}");
|
||||
|
||||
let image = image::open(path).expect("file exists");
|
||||
let binaryMap = BinaryBitmap::new(Rc::new(GlobalHistogramBinarizer::new(Box::new(
|
||||
let binaryMap = BinaryBitmap::new(GlobalHistogramBinarizer::new(
|
||||
BufferedImageLuminanceSource::new(image),
|
||||
))));
|
||||
let rowNumber = binaryMap.getHeight() / 2;
|
||||
let row = binaryMap.getBlackRow(rowNumber).expect("row");
|
||||
));
|
||||
let rowNumber = binaryMap.get_height() / 2;
|
||||
let row = binaryMap.get_black_row(rowNumber).expect("row");
|
||||
|
||||
// let pairs = Vec::new();
|
||||
// try {
|
||||
@@ -29,7 +29,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
use std::{collections::HashMap, rc::Rc};
|
||||
use std::collections::HashMap;
|
||||
|
||||
use crate::{
|
||||
client::result::{ExpandedProductParsedRXingResult, ParsedClientResult},
|
||||
@@ -71,15 +71,15 @@ fn assertCorrectImage2result(fileName: &str, expected: ExpandedProductParsedRXin
|
||||
let path = format!("test_resources/blackbox/rssexpanded-1/{fileName}");
|
||||
|
||||
let image = image::open(path).expect("image must exist");
|
||||
let binaryMap = BinaryBitmap::new(Rc::new(GlobalHistogramBinarizer::new(Box::new(
|
||||
let binaryMap = BinaryBitmap::new(GlobalHistogramBinarizer::new(
|
||||
BufferedImageLuminanceSource::new(image),
|
||||
))));
|
||||
let rowNumber = binaryMap.getHeight() / 2;
|
||||
let row = binaryMap.getBlackRow(rowNumber).expect("get row");
|
||||
));
|
||||
let rowNumber = binaryMap.get_height() / 2;
|
||||
let row = binaryMap.get_black_row(rowNumber).expect("get row");
|
||||
|
||||
let mut rssExpandedReader = RSSExpandedReader::new();
|
||||
let theRXingResult = rssExpandedReader
|
||||
.decodeRow(rowNumber as u32, &row, &HashMap::new())
|
||||
.decode_row(rowNumber as u32, &row, &HashMap::new())
|
||||
.expect("must decode");
|
||||
|
||||
assert_eq!(
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
* http://www.piramidepse.com/
|
||||
*/
|
||||
|
||||
use std::{collections::HashMap, rc::Rc};
|
||||
use std::collections::HashMap;
|
||||
|
||||
use crate::{
|
||||
common::GlobalHistogramBinarizer,
|
||||
@@ -184,15 +184,15 @@ fn assertCorrectImage2string(fileName: &str, expected: &str) {
|
||||
let path = format!("test_resources/blackbox/rssexpanded-1/{fileName}");
|
||||
|
||||
let image = image::open(path).expect("load image");
|
||||
let binaryMap = BinaryBitmap::new(Rc::new(GlobalHistogramBinarizer::new(Box::new(
|
||||
let binaryMap = BinaryBitmap::new(GlobalHistogramBinarizer::new(
|
||||
BufferedImageLuminanceSource::new(image),
|
||||
))));
|
||||
let rowNumber = binaryMap.getHeight() / 2;
|
||||
let row = binaryMap.getBlackRow(rowNumber).expect("get row");
|
||||
));
|
||||
let rowNumber = binaryMap.get_height() / 2;
|
||||
let row = binaryMap.get_black_row(rowNumber).expect("get row");
|
||||
|
||||
let mut rssExpandedReader = RSSExpandedReader::new();
|
||||
let result = rssExpandedReader
|
||||
.decodeRow(rowNumber as u32, &row, &HashMap::new())
|
||||
.decode_row(rowNumber as u32, &row, &HashMap::new())
|
||||
.expect("should decode");
|
||||
|
||||
assert_eq!(&BarcodeFormat::RSS_EXPANDED, result.getBarcodeFormat());
|
||||
|
||||
@@ -24,8 +24,6 @@
|
||||
* http://www.piramidepse.com/
|
||||
*/
|
||||
|
||||
use std::rc::Rc;
|
||||
|
||||
use crate::{
|
||||
common::GlobalHistogramBinarizer,
|
||||
oned::rss::{DataCharacterTrait, FinderPattern},
|
||||
@@ -42,11 +40,11 @@ use super::RSSExpandedReader;
|
||||
#[test]
|
||||
fn testFindFinderPatterns() {
|
||||
let image = readImage("2.png");
|
||||
let binaryMap = BinaryBitmap::new(Rc::new(GlobalHistogramBinarizer::new(Box::new(
|
||||
let binaryMap = BinaryBitmap::new(GlobalHistogramBinarizer::new(
|
||||
BufferedImageLuminanceSource::new(image),
|
||||
))));
|
||||
let rowNumber = binaryMap.getHeight() as u32 / 2;
|
||||
let row = binaryMap.getBlackRow(rowNumber as usize).expect("ok");
|
||||
));
|
||||
let rowNumber = binaryMap.get_height() as u32 / 2;
|
||||
let row = binaryMap.get_black_row(rowNumber as usize).expect("ok");
|
||||
let mut previousPairs = Vec::new(); //new ArrayList<>();
|
||||
|
||||
let mut rssExpandedReader = RSSExpandedReader::new();
|
||||
@@ -88,11 +86,11 @@ fn testFindFinderPatterns() {
|
||||
#[test]
|
||||
fn testRetrieveNextPairPatterns() {
|
||||
let image = readImage("3.png");
|
||||
let binaryMap = BinaryBitmap::new(Rc::new(GlobalHistogramBinarizer::new(Box::new(
|
||||
let binaryMap = BinaryBitmap::new(GlobalHistogramBinarizer::new(
|
||||
BufferedImageLuminanceSource::new(image),
|
||||
))));
|
||||
let rowNumber = binaryMap.getHeight() as u32 / 2;
|
||||
let row = binaryMap.getBlackRow(rowNumber as usize).expect("create");
|
||||
));
|
||||
let rowNumber = binaryMap.get_height() as u32 / 2;
|
||||
let row = binaryMap.get_black_row(rowNumber as usize).expect("create");
|
||||
let mut previousPairs = Vec::new(); //new ArrayList<>();
|
||||
|
||||
let mut rssExpandedReader = RSSExpandedReader::new();
|
||||
@@ -116,11 +114,11 @@ fn testRetrieveNextPairPatterns() {
|
||||
#[test]
|
||||
fn testDecodeCheckCharacter() {
|
||||
let image = readImage("3.png");
|
||||
let binaryMap = BinaryBitmap::new(Rc::new(GlobalHistogramBinarizer::new(Box::new(
|
||||
let binaryMap = BinaryBitmap::new(GlobalHistogramBinarizer::new(
|
||||
BufferedImageLuminanceSource::new(image.clone()),
|
||||
))));
|
||||
));
|
||||
let row = binaryMap
|
||||
.getBlackRow(binaryMap.getHeight() / 2)
|
||||
.get_black_row(binaryMap.get_height() / 2)
|
||||
.expect("create");
|
||||
|
||||
let startEnd = [145, 243]; //image pixels where the A1 pattern starts (at 124) and ends (at 214)
|
||||
@@ -144,11 +142,11 @@ fn testDecodeCheckCharacter() {
|
||||
#[test]
|
||||
fn testDecodeDataCharacter() {
|
||||
let image = readImage("3.png");
|
||||
let binaryMap = BinaryBitmap::new(Rc::new(GlobalHistogramBinarizer::new(Box::new(
|
||||
let binaryMap = BinaryBitmap::new(GlobalHistogramBinarizer::new(
|
||||
BufferedImageLuminanceSource::new(image.clone()),
|
||||
))));
|
||||
));
|
||||
let row = binaryMap
|
||||
.getBlackRow(binaryMap.getHeight() / 2)
|
||||
.get_black_row(binaryMap.get_height() / 2)
|
||||
.expect("create");
|
||||
|
||||
let startEnd = [145, 243]; //image pixels where the A1 pattern starts (at 124) and ends (at 214)
|
||||
|
||||
@@ -29,14 +29,14 @@ use std::collections::HashMap;
|
||||
use crate::{
|
||||
common::{BitArray, Result},
|
||||
oned::{
|
||||
recordPattern, recordPatternInReverse,
|
||||
record_pattern, record_pattern_in_reverse,
|
||||
rss::{
|
||||
rss_utils, AbstractRSSReaderTrait, DataCharacter, DataCharacterTrait, FinderPattern,
|
||||
Pair,
|
||||
},
|
||||
OneDReader,
|
||||
},
|
||||
BarcodeFormat, DecodeHintType, DecodeHintValue, DecodingHintDictionary, Exceptions,
|
||||
BarcodeFormat, Binarizer, DecodeHintType, DecodeHintValue, DecodingHintDictionary, Exceptions,
|
||||
RXingResult, RXingResultMetadataType, RXingResultMetadataValue, Reader,
|
||||
};
|
||||
|
||||
@@ -151,7 +151,7 @@ pub struct RSSExpandedReader {
|
||||
}
|
||||
impl AbstractRSSReaderTrait for RSSExpandedReader {}
|
||||
impl OneDReader for RSSExpandedReader {
|
||||
fn decodeRow(
|
||||
fn decode_row(
|
||||
&mut self,
|
||||
rowNumber: u32,
|
||||
row: &crate::common::BitArray,
|
||||
@@ -173,26 +173,26 @@ impl OneDReader for RSSExpandedReader {
|
||||
}
|
||||
}
|
||||
impl Reader for RSSExpandedReader {
|
||||
fn decode(&mut self, image: &mut crate::BinaryBitmap) -> Result<crate::RXingResult> {
|
||||
fn decode<B: Binarizer>(&mut self, image: &mut crate::BinaryBitmap<B>) -> Result<RXingResult> {
|
||||
self.decode_with_hints(image, &HashMap::new())
|
||||
}
|
||||
|
||||
// Note that we don't try rotation without the try harder flag, even if rotation was supported.
|
||||
fn decode_with_hints(
|
||||
fn decode_with_hints<B: Binarizer>(
|
||||
&mut self,
|
||||
image: &mut crate::BinaryBitmap,
|
||||
image: &mut crate::BinaryBitmap<B>,
|
||||
hints: &DecodingHintDictionary,
|
||||
) -> Result<crate::RXingResult> {
|
||||
if let Ok(res) = self.doDecode(image, hints) {
|
||||
if let Ok(res) = self._do_decode(image, hints) {
|
||||
Ok(res)
|
||||
} else {
|
||||
let tryHarder = matches!(
|
||||
hints.get(&DecodeHintType::TRY_HARDER),
|
||||
Some(DecodeHintValue::TryHarder(true))
|
||||
);
|
||||
if tryHarder && image.isRotateSupported() {
|
||||
let mut rotatedImage = image.rotateCounterClockwise();
|
||||
let mut result = self.doDecode(&mut rotatedImage, hints)?;
|
||||
if tryHarder && image.is_rotate_supported() {
|
||||
let mut rotatedImage = image.rotate_counter_clockwise();
|
||||
let mut result = self._do_decode(&mut rotatedImage, hints)?;
|
||||
// Record that we found it rotated 90 degrees CCW / 270 degrees CW
|
||||
let metadata = result.getRXingResultMetadata();
|
||||
let mut orientation = 270;
|
||||
@@ -213,7 +213,7 @@ impl Reader for RSSExpandedReader {
|
||||
RXingResultMetadataValue::Orientation(orientation),
|
||||
);
|
||||
// Update result points
|
||||
let height = rotatedImage.getHeight();
|
||||
let height = rotatedImage.get_height();
|
||||
|
||||
let total_points = result.getPoints().len();
|
||||
let points = result.getPointsMut();
|
||||
@@ -684,7 +684,7 @@ impl RSSExpandedReader {
|
||||
// counters[2] = 0;
|
||||
// counters[3] = 0;
|
||||
|
||||
let width = row.getSize();
|
||||
let width = row.get_size();
|
||||
|
||||
let mut rowOffset;
|
||||
if forcedOffset >= 0 {
|
||||
@@ -823,9 +823,9 @@ impl RSSExpandedReader {
|
||||
counters.fill(0);
|
||||
|
||||
if leftChar {
|
||||
recordPatternInReverse(row, pattern.getStartEnd()[0], counters)?;
|
||||
record_pattern_in_reverse(row, pattern.getStartEnd()[0], counters)?;
|
||||
} else {
|
||||
recordPattern(row, pattern.getStartEnd()[1], counters)?;
|
||||
record_pattern(row, pattern.getStartEnd()[1], counters)?;
|
||||
// reverse it
|
||||
counters.reverse();
|
||||
// let mut i = 0;
|
||||
|
||||
@@ -39,8 +39,8 @@ fn testDecodingRowByRow() {
|
||||
|
||||
let binaryMap = test_case_util::getBinaryBitmap("1000.png");
|
||||
|
||||
let firstRowNumber = binaryMap.getHeight() / 3;
|
||||
let firstRow = binaryMap.getBlackRow(firstRowNumber).expect("get row");
|
||||
let firstRowNumber = binaryMap.get_height() / 3;
|
||||
let firstRow = binaryMap.get_black_row(firstRowNumber).expect("get row");
|
||||
|
||||
// let tester = ;
|
||||
|
||||
@@ -72,9 +72,9 @@ fn testDecodingRowByRow() {
|
||||
.unwrap()
|
||||
.getStartEndMut()[1] = 0;
|
||||
|
||||
let secondRowNumber = 2 * binaryMap.getHeight() / 3;
|
||||
let secondRowNumber = 2 * binaryMap.get_height() / 3;
|
||||
let mut secondRow = binaryMap
|
||||
.getBlackRow(secondRowNumber)
|
||||
.get_black_row(secondRowNumber)
|
||||
.expect("get row")
|
||||
.into_owned();
|
||||
|
||||
|
||||
@@ -24,8 +24,6 @@
|
||||
* http://www.piramidepse.com/
|
||||
*/
|
||||
|
||||
use std::rc::Rc;
|
||||
|
||||
use image::DynamicImage;
|
||||
|
||||
use crate::{common::GlobalHistogramBinarizer, BinaryBitmap, BufferedImageLuminanceSource};
|
||||
@@ -36,10 +34,12 @@ fn getBufferedImage(fileName: &str) -> DynamicImage {
|
||||
image::open(path).expect("load image")
|
||||
}
|
||||
|
||||
pub(crate) fn getBinaryBitmap(fileName: &str) -> BinaryBitmap {
|
||||
pub(crate) fn getBinaryBitmap(
|
||||
fileName: &str,
|
||||
) -> BinaryBitmap<GlobalHistogramBinarizer<BufferedImageLuminanceSource>> {
|
||||
let bufferedImage = getBufferedImage(fileName);
|
||||
|
||||
BinaryBitmap::new(Rc::new(GlobalHistogramBinarizer::new(Box::new(
|
||||
BinaryBitmap::new(GlobalHistogramBinarizer::new(
|
||||
BufferedImageLuminanceSource::new(bufferedImage),
|
||||
))))
|
||||
))
|
||||
}
|
||||
|
||||
@@ -19,8 +19,8 @@ use std::collections::HashMap;
|
||||
use crate::{
|
||||
common::{BitArray, Result},
|
||||
oned::{one_d_reader, OneDReader},
|
||||
point, BarcodeFormat, DecodeHintType, DecodeHintValue, DecodingHintDictionary, Exceptions,
|
||||
RXingResult, RXingResultMetadataType, RXingResultMetadataValue, Reader,
|
||||
point, BarcodeFormat, Binarizer, DecodeHintType, DecodeHintValue, DecodingHintDictionary,
|
||||
Exceptions, RXingResult, RXingResultMetadataType, RXingResultMetadataValue, Reader,
|
||||
};
|
||||
|
||||
use super::{
|
||||
@@ -45,12 +45,12 @@ pub struct RSS14Reader {
|
||||
impl AbstractRSSReaderTrait for RSS14Reader {}
|
||||
|
||||
impl OneDReader for RSS14Reader {
|
||||
fn decodeRow(
|
||||
fn decode_row(
|
||||
&mut self,
|
||||
rowNumber: u32,
|
||||
row: &crate::common::BitArray,
|
||||
hints: &crate::DecodingHintDictionary,
|
||||
) -> Result<crate::RXingResult> {
|
||||
row: &BitArray,
|
||||
hints: &DecodingHintDictionary,
|
||||
) -> Result<RXingResult> {
|
||||
let mut row = row.clone();
|
||||
let leftPair = self.decodePair(&row, false, rowNumber, hints);
|
||||
Self::addOrTally(&mut self.possibleLeftPairs, leftPair);
|
||||
@@ -73,26 +73,26 @@ impl OneDReader for RSS14Reader {
|
||||
}
|
||||
}
|
||||
impl Reader for RSS14Reader {
|
||||
fn decode(&mut self, image: &mut crate::BinaryBitmap) -> Result<crate::RXingResult> {
|
||||
fn decode<B: Binarizer>(&mut self, image: &mut crate::BinaryBitmap<B>) -> Result<RXingResult> {
|
||||
self.decode_with_hints(image, &HashMap::new())
|
||||
}
|
||||
|
||||
// Note that we don't try rotation without the try harder flag, even if rotation was supported.
|
||||
fn decode_with_hints(
|
||||
fn decode_with_hints<B: Binarizer>(
|
||||
&mut self,
|
||||
image: &mut crate::BinaryBitmap,
|
||||
image: &mut crate::BinaryBitmap<B>,
|
||||
hints: &DecodingHintDictionary,
|
||||
) -> Result<crate::RXingResult> {
|
||||
if let Ok(res) = self.doDecode(image, hints) {
|
||||
if let Ok(res) = self._do_decode(image, hints) {
|
||||
Ok(res)
|
||||
} else {
|
||||
let tryHarder = matches!(
|
||||
hints.get(&DecodeHintType::TRY_HARDER),
|
||||
Some(DecodeHintValue::TryHarder(true))
|
||||
);
|
||||
if tryHarder && image.isRotateSupported() {
|
||||
let mut rotatedImage = image.rotateCounterClockwise();
|
||||
let mut result = self.doDecode(&mut rotatedImage, hints)?;
|
||||
if tryHarder && image.is_rotate_supported() {
|
||||
let mut rotatedImage = image.rotate_counter_clockwise();
|
||||
let mut result = self._do_decode(&mut rotatedImage, hints)?;
|
||||
// Record that we found it rotated 90 degrees CCW / 270 degrees CW
|
||||
let metadata = result.getRXingResultMetadata();
|
||||
let mut orientation = 270;
|
||||
@@ -113,7 +113,7 @@ impl Reader for RSS14Reader {
|
||||
RXingResultMetadataValue::Orientation(orientation),
|
||||
);
|
||||
// Update result points
|
||||
let height = rotatedImage.getHeight();
|
||||
let height = rotatedImage.get_height();
|
||||
let total_points = result.getPoints().len();
|
||||
let points = result.getPointsMut();
|
||||
for point in points.iter_mut().take(total_points) {
|
||||
@@ -257,7 +257,7 @@ impl RSS14Reader {
|
||||
let mut center: f32 = (startEnd[0] + startEnd[1] - 1) as f32 / 2.0;
|
||||
if right {
|
||||
// row is actually reversed
|
||||
center = row.getSize() as f32 - 1.0 - center;
|
||||
center = row.get_size() as f32 - 1.0 - center;
|
||||
}
|
||||
cb(point(center, rowNumber as f32));
|
||||
}
|
||||
@@ -287,9 +287,9 @@ impl RSS14Reader {
|
||||
counters.fill(0);
|
||||
|
||||
if outsideChar {
|
||||
one_d_reader::recordPatternInReverse(row, pattern.getStartEnd()[0], counters)?;
|
||||
one_d_reader::record_pattern_in_reverse(row, pattern.getStartEnd()[0], counters)?;
|
||||
} else {
|
||||
one_d_reader::recordPattern(row, pattern.getStartEnd()[1], counters)?;
|
||||
one_d_reader::record_pattern(row, pattern.getStartEnd()[1], counters)?;
|
||||
// reverse it
|
||||
counters.reverse();
|
||||
// let mut i = 0;
|
||||
@@ -379,7 +379,7 @@ impl RSS14Reader {
|
||||
let counters = &mut self.decodeFinderCounters;
|
||||
counters.fill(0);
|
||||
|
||||
let width = row.getSize();
|
||||
let width = row.get_size();
|
||||
let mut isWhite = false;
|
||||
let mut rowOffset = 0;
|
||||
while rowOffset < width {
|
||||
@@ -445,8 +445,8 @@ impl RSS14Reader {
|
||||
let mut end = startEnd[1];
|
||||
if right {
|
||||
// row is actually reversed
|
||||
start = row.getSize() - 1 - start;
|
||||
end = row.getSize() - 1 - end;
|
||||
start = row.get_size() - 1 - start;
|
||||
end = row.get_size() - 1 - end;
|
||||
}
|
||||
|
||||
Ok(FinderPattern::new(
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
use crate::{common::Result, BarcodeFormat, Exceptions, RXingResult, Reader};
|
||||
use crate::{common::Result, BarcodeFormat, Binarizer, Exceptions, RXingResult, Reader};
|
||||
|
||||
use super::{EAN13Reader, OneDReader, UPCEANReader};
|
||||
|
||||
@@ -28,32 +28,50 @@ use super::{EAN13Reader, OneDReader, UPCEANReader};
|
||||
pub struct UPCAReader(EAN13Reader);
|
||||
|
||||
impl Reader for UPCAReader {
|
||||
fn decode(&mut self, image: &mut crate::BinaryBitmap) -> Result<crate::RXingResult> {
|
||||
fn decode<B: Binarizer>(&mut self, image: &mut crate::BinaryBitmap<B>) -> Result<RXingResult> {
|
||||
Self::maybeReturnRXingResult(self.0.decode(image)?)
|
||||
}
|
||||
|
||||
fn decode_with_hints(
|
||||
fn decode_with_hints<B: Binarizer>(
|
||||
&mut self,
|
||||
image: &mut crate::BinaryBitmap,
|
||||
image: &mut crate::BinaryBitmap<B>,
|
||||
hints: &crate::DecodingHintDictionary,
|
||||
) -> Result<crate::RXingResult> {
|
||||
) -> Result<RXingResult> {
|
||||
Self::maybeReturnRXingResult(self.0.decode_with_hints(image, hints)?)
|
||||
}
|
||||
}
|
||||
|
||||
impl OneDReader for UPCAReader {
|
||||
fn decodeRow(
|
||||
fn decode_row(
|
||||
&mut self,
|
||||
rowNumber: u32,
|
||||
row: &crate::common::BitArray,
|
||||
hints: &crate::DecodingHintDictionary,
|
||||
) -> Result<crate::RXingResult> {
|
||||
Self::maybeReturnRXingResult(self.0.decodeRow(rowNumber, row, hints)?)
|
||||
) -> Result<RXingResult> {
|
||||
Self::maybeReturnRXingResult(self.0.decode_row(rowNumber, row, hints)?)
|
||||
}
|
||||
}
|
||||
|
||||
impl UPCEANReader for UPCAReader {
|
||||
fn getBarcodeFormat(&self) -> crate::BarcodeFormat {
|
||||
fn decodeRowWithGuardRange(
|
||||
&self,
|
||||
rowNumber: u32,
|
||||
row: &crate::common::BitArray,
|
||||
startGuardRange: &[usize; 2],
|
||||
hints: &crate::DecodingHintDictionary,
|
||||
) -> Result<RXingResult>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
Self::maybeReturnRXingResult(self.0.decodeRowWithGuardRange(
|
||||
rowNumber,
|
||||
row,
|
||||
startGuardRange,
|
||||
hints,
|
||||
)?)
|
||||
}
|
||||
|
||||
fn getBarcodeFormat(&self) -> BarcodeFormat {
|
||||
BarcodeFormat::UPC_A
|
||||
}
|
||||
|
||||
@@ -65,24 +83,6 @@ impl UPCEANReader for UPCAReader {
|
||||
) -> Result<usize> {
|
||||
self.0.decodeMiddle(row, startRange, resultString)
|
||||
}
|
||||
|
||||
fn decodeRowWithGuardRange(
|
||||
&self,
|
||||
rowNumber: u32,
|
||||
row: &crate::common::BitArray,
|
||||
startGuardRange: &[usize; 2],
|
||||
hints: &crate::DecodingHintDictionary,
|
||||
) -> Result<crate::RXingResult>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
Self::maybeReturnRXingResult(self.0.decodeRowWithGuardRange(
|
||||
rowNumber,
|
||||
row,
|
||||
startGuardRange,
|
||||
hints,
|
||||
)?)
|
||||
}
|
||||
}
|
||||
|
||||
impl UPCAReader {
|
||||
|
||||
@@ -41,7 +41,7 @@ impl UPCEANReader for UPCEReader {
|
||||
) -> Result<usize> {
|
||||
let mut counters = [0_u32; 4];
|
||||
|
||||
let end = row.getSize();
|
||||
let end = row.get_size();
|
||||
let mut rowOffset = startRange[1];
|
||||
|
||||
let mut lgPatternFound = 0;
|
||||
|
||||
@@ -73,7 +73,7 @@ impl UPCEANExtension2Support {
|
||||
let mut counters = self.decodeMiddleCounters;
|
||||
counters.fill(0);
|
||||
|
||||
let end = row.getSize();
|
||||
let end = row.get_size();
|
||||
let mut rowOffset = startRange[1] as usize;
|
||||
|
||||
let mut checkParity = 0;
|
||||
|
||||
@@ -73,7 +73,7 @@ impl UPCEANExtension5Support {
|
||||
resultString: &mut String,
|
||||
) -> Result<u32> {
|
||||
let mut counters = [0_u32; 4];
|
||||
let end = row.getSize();
|
||||
let end = row.get_size();
|
||||
let mut rowOffset = startRange[1];
|
||||
|
||||
let mut lgPatternFound = 0;
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
use crate::{
|
||||
common::{BitArray, Result},
|
||||
point, BarcodeFormat, DecodeHintType, DecodeHintValue, Exceptions, RXingResult,
|
||||
point, BarcodeFormat, Binarizer, DecodeHintType, DecodeHintValue, Exceptions, RXingResult,
|
||||
RXingResultMetadataType, RXingResultMetadataValue, Reader,
|
||||
};
|
||||
|
||||
@@ -101,7 +101,7 @@ pub const L_AND_G_PATTERNS: [[u32; 4]; 20] = {
|
||||
* @author alasdair@google.com (Alasdair Mackintosh)
|
||||
*/
|
||||
pub trait UPCEANReader: OneDReader {
|
||||
fn findStartGuardPattern(&self, row: &BitArray) -> Result<[usize; 2]> {
|
||||
fn find_start_guard_pattern(&self, row: &BitArray) -> Result<[usize; 2]> {
|
||||
let mut foundStart = false;
|
||||
let mut startRange = [0; 2];
|
||||
let mut nextStart = 0;
|
||||
@@ -182,7 +182,7 @@ pub trait UPCEANReader: OneDReader {
|
||||
// spec might want more whitespace, but in practice this is the maximum we can count on.
|
||||
let end = endRange[1];
|
||||
let quietEnd = end + (end - endRange[0]);
|
||||
if quietEnd >= row.getSize() || !row.isRange(end, quietEnd, false)? {
|
||||
if quietEnd >= row.get_size() || !row.isRange(end, quietEnd, false)? {
|
||||
return Err(Exceptions::NOT_FOUND);
|
||||
}
|
||||
|
||||
@@ -382,7 +382,7 @@ pub trait UPCEANReader: OneDReader {
|
||||
pattern: &[u32],
|
||||
counters: &mut [u32],
|
||||
) -> Result<[usize; 2]> {
|
||||
let width = row.getSize();
|
||||
let width = row.get_size();
|
||||
let rowOffset = if whiteFirst {
|
||||
row.getNextUnset(rowOffset)
|
||||
} else {
|
||||
@@ -398,7 +398,7 @@ pub trait UPCEANReader: OneDReader {
|
||||
counters[counterPosition] += 1;
|
||||
} else {
|
||||
if counterPosition == patternLength - 1 {
|
||||
if one_d_reader::patternMatchVariance(
|
||||
if one_d_reader::pattern_match_variance(
|
||||
counters,
|
||||
pattern,
|
||||
MAX_INDIVIDUAL_VARIANCE,
|
||||
@@ -443,13 +443,13 @@ pub trait UPCEANReader: OneDReader {
|
||||
rowOffset: usize,
|
||||
patterns: &[[u32; 4]],
|
||||
) -> Result<usize> {
|
||||
one_d_reader::recordPattern(row, rowOffset, counters)?;
|
||||
one_d_reader::record_pattern(row, rowOffset, counters)?;
|
||||
let mut bestVariance = MAX_AVG_VARIANCE; // worst variance we'll accept
|
||||
let mut bestMatch = -1_isize;
|
||||
let max = patterns.len();
|
||||
for (i, pattern) in patterns.iter().enumerate().take(max) {
|
||||
let variance: f32 =
|
||||
one_d_reader::patternMatchVariance(counters, pattern, MAX_INDIVIDUAL_VARIANCE);
|
||||
one_d_reader::pattern_match_variance(counters, pattern, MAX_INDIVIDUAL_VARIANCE);
|
||||
if variance < bestVariance {
|
||||
bestVariance = variance;
|
||||
bestMatch = i as isize;
|
||||
@@ -503,7 +503,7 @@ impl UPCEANReader for StandInStruct {
|
||||
}
|
||||
}
|
||||
impl OneDReader for StandInStruct {
|
||||
fn decodeRow(
|
||||
fn decode_row(
|
||||
&mut self,
|
||||
_rowNumber: u32,
|
||||
_row: &BitArray,
|
||||
@@ -514,13 +514,13 @@ impl OneDReader for StandInStruct {
|
||||
}
|
||||
|
||||
impl Reader for StandInStruct {
|
||||
fn decode(&mut self, _image: &mut crate::BinaryBitmap) -> Result<RXingResult> {
|
||||
fn decode<B: Binarizer>(&mut self, _image: &mut crate::BinaryBitmap<B>) -> Result<RXingResult> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn decode_with_hints(
|
||||
fn decode_with_hints<B: Binarizer>(
|
||||
&mut self,
|
||||
_image: &mut crate::BinaryBitmap,
|
||||
_image: &mut crate::BinaryBitmap<B>,
|
||||
_hints: &crate::DecodingHintDictionary,
|
||||
) -> Result<RXingResult> {
|
||||
todo!()
|
||||
|
||||
@@ -21,7 +21,7 @@ use super::{BoundingBox, Codeword, DetectionRXingResultRowIndicatorColumn};
|
||||
const MAX_NEARBY_DISTANCE: u32 = 5;
|
||||
|
||||
pub trait DetectionRXingResultColumnTrait {
|
||||
fn new(boundingBox: Rc<BoundingBox>) -> DetectionRXingResultColumn
|
||||
fn new_column(boundingBox: Rc<BoundingBox>) -> DetectionRXingResultColumn
|
||||
where
|
||||
Self: Sized;
|
||||
fn new_with_is_left(boundingBox: Rc<BoundingBox>, isLeft: bool) -> DetectionRXingResultColumn
|
||||
@@ -48,7 +48,7 @@ pub struct DetectionRXingResultColumn {
|
||||
}
|
||||
|
||||
impl DetectionRXingResultColumnTrait for DetectionRXingResultColumn {
|
||||
fn new(boundingBox: Rc<BoundingBox>) -> DetectionRXingResultColumn {
|
||||
fn new_column(boundingBox: Rc<BoundingBox>) -> DetectionRXingResultColumn {
|
||||
DetectionRXingResultColumn {
|
||||
boundingBox: BoundingBox::from_other(boundingBox.clone()),
|
||||
codewords: vec![None; (boundingBox.getMaxY() - boundingBox.getMinY() + 1) as usize],
|
||||
|
||||
@@ -44,9 +44,9 @@ const MAX_EC_CODEWORDS: u32 = 512;
|
||||
// than it should be. This can happen if the scanner used a bad blackpoint.
|
||||
pub fn decode(
|
||||
image: &BitMatrix,
|
||||
imageTopLeft: Option<Point>,
|
||||
image_top_left: Option<Point>,
|
||||
imageBottomLeft: Option<Point>,
|
||||
imageTopRight: Option<Point>,
|
||||
image_top_right: Option<Point>,
|
||||
imageBottomRight: Option<Point>,
|
||||
minCodewordWidth: u32,
|
||||
maxCodewordWidth: u32,
|
||||
@@ -55,30 +55,30 @@ pub fn decode(
|
||||
let mut maxCodewordWidth = maxCodewordWidth;
|
||||
let mut boundingBox = Rc::new(BoundingBox::new(
|
||||
Rc::new(image.clone()),
|
||||
imageTopLeft,
|
||||
image_top_left,
|
||||
imageBottomLeft,
|
||||
imageTopRight,
|
||||
image_top_right,
|
||||
imageBottomRight,
|
||||
)?);
|
||||
let mut leftRowIndicatorColumn = None;
|
||||
let mut rightRowIndicatorColumn = None;
|
||||
let mut detectionRXingResult = None;
|
||||
for firstPass in [true, false] {
|
||||
if imageTopLeft.is_some() {
|
||||
if let Some(image_top_left) = image_top_left {
|
||||
leftRowIndicatorColumn = Some(getRowIndicatorColumn(
|
||||
image,
|
||||
boundingBox.clone(),
|
||||
imageTopLeft.unwrap(),
|
||||
image_top_left,
|
||||
true,
|
||||
minCodewordWidth,
|
||||
maxCodewordWidth,
|
||||
));
|
||||
}
|
||||
if imageTopRight.is_some() {
|
||||
if let Some(image_top_right) = image_top_right {
|
||||
rightRowIndicatorColumn = Some(getRowIndicatorColumn(
|
||||
image,
|
||||
boundingBox.clone(),
|
||||
imageTopRight.unwrap(),
|
||||
image_top_right,
|
||||
false,
|
||||
minCodewordWidth,
|
||||
maxCodewordWidth,
|
||||
@@ -129,7 +129,7 @@ pub fn decode(
|
||||
{
|
||||
DetectionRXingResultColumn::new_with_is_left(boundingBox.clone(), barcodeColumn == 0)
|
||||
} else {
|
||||
DetectionRXingResultColumn::new(boundingBox.clone())
|
||||
DetectionRXingResultColumn::new_column(boundingBox.clone())
|
||||
};
|
||||
|
||||
detectionRXingResult
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
use crate::{
|
||||
common::{BitMatrix, Result},
|
||||
point, BinaryBitmap, DecodingHintDictionary, Exceptions, Point,
|
||||
point, Binarizer, BinaryBitmap, DecodingHintDictionary, Exceptions, Point,
|
||||
};
|
||||
|
||||
use std::borrow::Cow;
|
||||
@@ -64,8 +64,8 @@ const ROTATIONS: [u32; 4] = [0, 180, 270, 90];
|
||||
* @return {@link PDF417DetectorRXingResult} encapsulating results of detecting a PDF417 code
|
||||
* @throws NotFoundException if no PDF417 Code can be found
|
||||
*/
|
||||
pub fn detect_with_hints(
|
||||
image: &mut BinaryBitmap,
|
||||
pub fn detect_with_hints<B: Binarizer>(
|
||||
image: &mut BinaryBitmap<B>,
|
||||
_hints: &DecodingHintDictionary,
|
||||
multiple: bool,
|
||||
) -> Result<PDF417DetectorRXingResult> {
|
||||
@@ -74,7 +74,7 @@ pub fn detect_with_hints(
|
||||
//boolean tryHarder = hints != null && hints.containsKey(DecodeHintType.TRY_HARDER);
|
||||
//let try_harder = matches!(hints.get(&DecodeHintType::TRY_HARDER), Some(DecodeHintValue::TryHarder(true)));
|
||||
|
||||
let originalMatrix = image.getBlackMatrix();
|
||||
let originalMatrix = image.get_black_matrix();
|
||||
for rotation in ROTATIONS {
|
||||
// for (int rotation : ROTATIONS) {
|
||||
let bitMatrix = applyRotation(originalMatrix, rotation)?;
|
||||
|
||||
@@ -217,11 +217,15 @@ pub fn encodeHighLevel(
|
||||
// User selected encoding mode
|
||||
match compaction {
|
||||
Compaction::TEXT => {
|
||||
encodeText(&input, p, len as u32, &mut sb, textSubMode)?;
|
||||
}
|
||||
Compaction::BYTE if autoECI => {
|
||||
encodeMultiECIBinary(&input, 0, input.length() as u32, TEXT_COMPACTION, &mut sb)?
|
||||
encodeText(input.as_ref(), p, len as u32, &mut sb, textSubMode)?;
|
||||
}
|
||||
Compaction::BYTE if autoECI => encodeMultiECIBinary(
|
||||
input.as_ref(),
|
||||
0,
|
||||
input.length() as u32,
|
||||
TEXT_COMPACTION,
|
||||
&mut sb,
|
||||
)?,
|
||||
Compaction::BYTE => {
|
||||
let msgBytes = encoding
|
||||
.as_ref()
|
||||
@@ -238,7 +242,7 @@ pub fn encodeHighLevel(
|
||||
}
|
||||
Compaction::NUMERIC => {
|
||||
sb.push(char::from_u32(LATCH_TO_NUMERIC).ok_or(Exceptions::PARSE)?);
|
||||
encodeNumeric(&input, p, len as u32, &mut sb)?;
|
||||
encodeNumeric(input.as_ref(), p, len as u32, &mut sb)?;
|
||||
}
|
||||
_ => {
|
||||
let mut encodingMode = TEXT_COMPACTION; //Default mode, see 4.4.2.1
|
||||
@@ -250,26 +254,26 @@ pub fn encodeHighLevel(
|
||||
if p >= len as u32 {
|
||||
break;
|
||||
}
|
||||
let n = determineConsecutiveDigitCount(&input, p)?;
|
||||
let n = determineConsecutiveDigitCount(input.as_ref(), p)?;
|
||||
if n >= 13 {
|
||||
sb.push(char::from_u32(LATCH_TO_NUMERIC).ok_or(Exceptions::PARSE)?);
|
||||
encodingMode = NUMERIC_COMPACTION;
|
||||
textSubMode = SUBMODE_ALPHA; //Reset after latch
|
||||
encodeNumeric(&input, p, n, &mut sb)?;
|
||||
encodeNumeric(input.as_ref(), p, n, &mut sb)?;
|
||||
p += n;
|
||||
} else {
|
||||
let t = determineConsecutiveTextCount(&input, p)?;
|
||||
let t = determineConsecutiveTextCount(input.as_ref(), p)?;
|
||||
if t >= 5 || n == len as u32 {
|
||||
if encodingMode != TEXT_COMPACTION {
|
||||
sb.push(char::from_u32(LATCH_TO_TEXT).ok_or(Exceptions::PARSE)?);
|
||||
encodingMode = TEXT_COMPACTION;
|
||||
textSubMode = SUBMODE_ALPHA; //start with submode alpha after latch
|
||||
}
|
||||
textSubMode = encodeText(&input, p, t, &mut sb, textSubMode)?;
|
||||
textSubMode = encodeText(input.as_ref(), p, t, &mut sb, textSubMode)?;
|
||||
p += t;
|
||||
} else {
|
||||
let mut b = determineConsecutiveBinaryCount(
|
||||
&input,
|
||||
input.as_ref(),
|
||||
p,
|
||||
if autoECI { None } else { encoding },
|
||||
)?;
|
||||
@@ -298,7 +302,13 @@ pub fn encodeHighLevel(
|
||||
if (bytes_ok && b == 1) && (encodingMode == TEXT_COMPACTION) {
|
||||
//Switch for one byte (instead of latch)
|
||||
if autoECI {
|
||||
encodeMultiECIBinary(&input, p, 1, TEXT_COMPACTION, &mut sb)?;
|
||||
encodeMultiECIBinary(
|
||||
input.as_ref(),
|
||||
p,
|
||||
1,
|
||||
TEXT_COMPACTION,
|
||||
&mut sb,
|
||||
)?;
|
||||
} else {
|
||||
encodeBinary(
|
||||
bytes.as_ref().ok_or(Exceptions::ILLEGAL_STATE)?,
|
||||
@@ -311,7 +321,13 @@ pub fn encodeHighLevel(
|
||||
} else {
|
||||
//Mode latch performed by encodeBinary()
|
||||
if autoECI {
|
||||
encodeMultiECIBinary(&input, p, p + b, encodingMode, &mut sb)?;
|
||||
encodeMultiECIBinary(
|
||||
input.as_ref(),
|
||||
p,
|
||||
p + b,
|
||||
encodingMode,
|
||||
&mut sb,
|
||||
)?;
|
||||
} else {
|
||||
encodeBinary(
|
||||
bytes.as_ref().ok_or(Exceptions::ILLEGAL_STATE)?,
|
||||
@@ -346,7 +362,7 @@ pub fn encodeHighLevel(
|
||||
* @return the text submode in which this method ends
|
||||
*/
|
||||
fn encodeText<T: ECIInput + ?Sized>(
|
||||
input: &Box<T>,
|
||||
input: &T,
|
||||
startpos: u32,
|
||||
count: u32,
|
||||
sb: &mut String,
|
||||
@@ -491,7 +507,7 @@ fn encodeText<T: ECIInput + ?Sized>(
|
||||
* @param sb receives the encoded codewords
|
||||
*/
|
||||
fn encodeMultiECIBinary<T: ECIInput + ?Sized>(
|
||||
input: &Box<T>,
|
||||
input: &T,
|
||||
startpos: u32,
|
||||
count: u32,
|
||||
startmode: u32,
|
||||
@@ -535,7 +551,7 @@ fn encodeMultiECIBinary<T: ECIInput + ?Sized>(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn subBytes<T: ECIInput + ?Sized>(input: &Box<T>, start: u32, end: u32) -> Result<Vec<u8>> {
|
||||
pub fn subBytes<T: ECIInput + ?Sized>(input: &T, start: u32, end: u32) -> Result<Vec<u8>> {
|
||||
let count = (end - start) as usize;
|
||||
let mut result = vec![0_u8; count];
|
||||
for i in start as usize..end as usize {
|
||||
@@ -598,7 +614,7 @@ fn encodeBinary(
|
||||
}
|
||||
|
||||
fn encodeNumeric<T: ECIInput + ?Sized>(
|
||||
input: &Box<T>,
|
||||
input: &T,
|
||||
startpos: u32,
|
||||
count: u32,
|
||||
sb: &mut String,
|
||||
@@ -679,10 +695,7 @@ fn isText(ch: char) -> bool {
|
||||
* @param startpos the start position within the input
|
||||
* @return the requested character count
|
||||
*/
|
||||
fn determineConsecutiveDigitCount<T: ECIInput + ?Sized>(
|
||||
input: &Box<T>,
|
||||
startpos: u32,
|
||||
) -> Result<u32> {
|
||||
fn determineConsecutiveDigitCount<T: ECIInput + ?Sized>(input: &T, startpos: u32) -> Result<u32> {
|
||||
let mut count = 0;
|
||||
let len = input.length();
|
||||
let mut idx = startpos as usize;
|
||||
@@ -703,10 +716,7 @@ fn determineConsecutiveDigitCount<T: ECIInput + ?Sized>(
|
||||
* @param startpos the start position within the input
|
||||
* @return the requested character count
|
||||
*/
|
||||
fn determineConsecutiveTextCount<T: ECIInput + ?Sized>(
|
||||
input: &Box<T>,
|
||||
startpos: u32,
|
||||
) -> Result<u32> {
|
||||
fn determineConsecutiveTextCount<T: ECIInput + ?Sized>(input: &T, startpos: u32) -> Result<u32> {
|
||||
let len = input.length();
|
||||
let mut idx = startpos as usize;
|
||||
while idx < len {
|
||||
@@ -745,7 +755,7 @@ fn determineConsecutiveTextCount<T: ECIInput + ?Sized>(
|
||||
* @return the requested character count
|
||||
*/
|
||||
fn determineConsecutiveBinaryCount<T: ECIInput + ?Sized + 'static>(
|
||||
input: &Box<T>,
|
||||
input: &T,
|
||||
startpos: u32,
|
||||
encoding: Option<EncodingRef>,
|
||||
) -> Result<u32> {
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use crate::{
|
||||
common::Result, multi::MultipleBarcodeReader, BarcodeFormat, BinaryBitmap,
|
||||
common::Result, multi::MultipleBarcodeReader, BarcodeFormat, Binarizer, BinaryBitmap,
|
||||
DecodingHintDictionary, Exceptions, Point, RXingResult, RXingResultMetadataType,
|
||||
RXingResultMetadataValue, Reader,
|
||||
};
|
||||
@@ -43,13 +43,13 @@ impl Reader for PDF417Reader {
|
||||
* @throws NotFoundException if a PDF417 code cannot be found,
|
||||
* @throws FormatException if a PDF417 cannot be decoded
|
||||
*/
|
||||
fn decode(&mut self, image: &mut crate::BinaryBitmap) -> Result<crate::RXingResult> {
|
||||
fn decode<B: Binarizer>(&mut self, image: &mut BinaryBitmap<B>) -> Result<RXingResult> {
|
||||
self.decode_with_hints(image, &HashMap::new())
|
||||
}
|
||||
|
||||
fn decode_with_hints(
|
||||
fn decode_with_hints<B: Binarizer>(
|
||||
&mut self,
|
||||
image: &mut crate::BinaryBitmap,
|
||||
image: &mut BinaryBitmap<B>,
|
||||
hints: &crate::DecodingHintDictionary,
|
||||
) -> Result<crate::RXingResult> {
|
||||
let result = Self::decode(image, hints, false)?;
|
||||
@@ -61,18 +61,18 @@ impl Reader for PDF417Reader {
|
||||
}
|
||||
|
||||
impl MultipleBarcodeReader for PDF417Reader {
|
||||
fn decode_multiple(
|
||||
fn decode_multiple<B: Binarizer>(
|
||||
&mut self,
|
||||
image: &mut crate::BinaryBitmap,
|
||||
) -> Result<Vec<crate::RXingResult>> {
|
||||
image: &mut BinaryBitmap<B>,
|
||||
) -> Result<Vec<RXingResult>> {
|
||||
self.decode_multiple_with_hints(image, &HashMap::new())
|
||||
}
|
||||
|
||||
fn decode_multiple_with_hints(
|
||||
fn decode_multiple_with_hints<B: Binarizer>(
|
||||
&mut self,
|
||||
image: &mut crate::BinaryBitmap,
|
||||
hints: &crate::DecodingHintDictionary,
|
||||
) -> Result<Vec<crate::RXingResult>> {
|
||||
image: &mut BinaryBitmap<B>,
|
||||
hints: &DecodingHintDictionary,
|
||||
) -> Result<Vec<RXingResult>> {
|
||||
Self::decode(image, hints, true)
|
||||
}
|
||||
}
|
||||
@@ -82,8 +82,8 @@ impl PDF417Reader {
|
||||
Self::default()
|
||||
}
|
||||
|
||||
fn decode(
|
||||
image: &mut BinaryBitmap,
|
||||
fn decode<B: Binarizer>(
|
||||
image: &mut BinaryBitmap<B>,
|
||||
hints: &DecodingHintDictionary,
|
||||
multiple: bool,
|
||||
) -> Result<Vec<RXingResult>> {
|
||||
|
||||
@@ -191,8 +191,8 @@ impl PlanarYUVLuminanceSource {
|
||||
}
|
||||
|
||||
pub fn renderThumbnail(&self) -> Vec<u8> {
|
||||
let width = self.getWidth() / THUMBNAIL_SCALE_FACTOR;
|
||||
let height = self.getHeight() / THUMBNAIL_SCALE_FACTOR;
|
||||
let width = self.get_width() / THUMBNAIL_SCALE_FACTOR;
|
||||
let height = self.get_height() / THUMBNAIL_SCALE_FACTOR;
|
||||
let mut pixels = vec![0; width * height];
|
||||
let yuv = &self.yuv_data;
|
||||
let mut input_offset = self.top * self.data_width + self.left;
|
||||
@@ -212,14 +212,14 @@ impl PlanarYUVLuminanceSource {
|
||||
* @return width of image from {@link #renderThumbnail()}
|
||||
*/
|
||||
pub fn getThumbnailWidth(&self) -> usize {
|
||||
self.getWidth() / THUMBNAIL_SCALE_FACTOR
|
||||
self.get_width() / THUMBNAIL_SCALE_FACTOR
|
||||
}
|
||||
|
||||
/**
|
||||
* @return height of image from {@link #renderThumbnail()}
|
||||
*/
|
||||
pub fn getThumbnailHeight(&self) -> usize {
|
||||
self.getHeight() / THUMBNAIL_SCALE_FACTOR
|
||||
self.get_height() / THUMBNAIL_SCALE_FACTOR
|
||||
}
|
||||
|
||||
fn reverseHorizontal(&mut self, width: usize, height: usize) {
|
||||
@@ -237,13 +237,13 @@ impl PlanarYUVLuminanceSource {
|
||||
}
|
||||
|
||||
impl LuminanceSource for PlanarYUVLuminanceSource {
|
||||
fn getRow(&self, y: usize) -> Vec<u8> {
|
||||
if y >= self.getHeight() {
|
||||
fn get_row(&self, y: usize) -> Vec<u8> {
|
||||
if y >= self.get_height() {
|
||||
// //throw new IllegalArgumentException("Requested row is outside the image: " + y);
|
||||
// panic!("Requested row is outside the image: {y}");
|
||||
return Vec::new();
|
||||
}
|
||||
let width = self.getWidth();
|
||||
let width = self.get_width();
|
||||
|
||||
let offset = (y + self.top) * self.data_width + self.left;
|
||||
|
||||
@@ -256,9 +256,9 @@ impl LuminanceSource for PlanarYUVLuminanceSource {
|
||||
row
|
||||
}
|
||||
|
||||
fn getMatrix(&self) -> Vec<u8> {
|
||||
let width = self.getWidth();
|
||||
let height = self.getHeight();
|
||||
fn get_matrix(&self) -> Vec<u8> {
|
||||
let width = self.get_width();
|
||||
let height = self.get_height();
|
||||
|
||||
// If the caller asks for the entire underlying image, save the copy and give them the
|
||||
// original data. The docs specifically warn that result.length must be ignored.
|
||||
@@ -298,26 +298,20 @@ impl LuminanceSource for PlanarYUVLuminanceSource {
|
||||
matrix
|
||||
}
|
||||
|
||||
fn getWidth(&self) -> usize {
|
||||
fn get_width(&self) -> usize {
|
||||
self.width
|
||||
}
|
||||
|
||||
fn getHeight(&self) -> usize {
|
||||
fn get_height(&self) -> usize {
|
||||
self.height
|
||||
}
|
||||
|
||||
fn isCropSupported(&self) -> bool {
|
||||
fn is_crop_supported(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn crop(
|
||||
&self,
|
||||
left: usize,
|
||||
top: usize,
|
||||
width: usize,
|
||||
height: usize,
|
||||
) -> Result<Box<dyn LuminanceSource>> {
|
||||
match PlanarYUVLuminanceSource::new_with_all(
|
||||
fn crop(&self, left: usize, top: usize, width: usize, height: usize) -> Result<Self> {
|
||||
PlanarYUVLuminanceSource::new_with_all(
|
||||
self.yuv_data.clone(),
|
||||
self.data_width,
|
||||
self.data_height,
|
||||
@@ -327,13 +321,11 @@ impl LuminanceSource for PlanarYUVLuminanceSource {
|
||||
height,
|
||||
false,
|
||||
self.invert,
|
||||
) {
|
||||
Ok(new) => Ok(Box::new(new)),
|
||||
Err(_err) => Err(Exceptions::UNSUPPORTED_OPERATION),
|
||||
}
|
||||
)
|
||||
.map_err(|_| Exceptions::UNSUPPORTED_OPERATION)
|
||||
}
|
||||
|
||||
fn isRotateSupported(&self) -> bool {
|
||||
fn is_rotate_supported(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
|
||||
@@ -310,7 +310,7 @@ fn decodeByteSegment(
|
||||
{
|
||||
encoding::all::ISO_8859_1
|
||||
} else {
|
||||
StringUtils::guessCharset(&readBytes, hints)
|
||||
StringUtils::guessCharset(&readBytes, hints).ok_or(Exceptions::ILLEGAL_STATE)?
|
||||
}
|
||||
} else {
|
||||
CharacterSetECI::getCharset(
|
||||
|
||||
@@ -39,43 +39,43 @@ fn testAppendBit() {
|
||||
assert_eq!(0, v.getSizeInBytes());
|
||||
// 1
|
||||
v.appendBit(true);
|
||||
assert_eq!(1, v.getSize());
|
||||
assert_eq!(1, v.get_size());
|
||||
assert_eq!(0x80000000, getUnsignedInt(&v));
|
||||
// 10
|
||||
v.appendBit(false);
|
||||
assert_eq!(2, v.getSize());
|
||||
assert_eq!(2, v.get_size());
|
||||
assert_eq!(0x80000000, getUnsignedInt(&v));
|
||||
// 101
|
||||
v.appendBit(true);
|
||||
assert_eq!(3, v.getSize());
|
||||
assert_eq!(3, v.get_size());
|
||||
assert_eq!(0xa0000000, getUnsignedInt(&v));
|
||||
// 1010
|
||||
v.appendBit(false);
|
||||
assert_eq!(4, v.getSize());
|
||||
assert_eq!(4, v.get_size());
|
||||
assert_eq!(0xa0000000, getUnsignedInt(&v));
|
||||
// 10101
|
||||
v.appendBit(true);
|
||||
assert_eq!(5, v.getSize());
|
||||
assert_eq!(5, v.get_size());
|
||||
assert_eq!(0xa8000000, getUnsignedInt(&v));
|
||||
// 101010
|
||||
v.appendBit(false);
|
||||
assert_eq!(6, v.getSize());
|
||||
assert_eq!(6, v.get_size());
|
||||
assert_eq!(0xa8000000, getUnsignedInt(&v));
|
||||
// 1010101
|
||||
v.appendBit(true);
|
||||
assert_eq!(7, v.getSize());
|
||||
assert_eq!(7, v.get_size());
|
||||
assert_eq!(0xaa000000, getUnsignedInt(&v));
|
||||
// 10101010
|
||||
v.appendBit(false);
|
||||
assert_eq!(8, v.getSize());
|
||||
assert_eq!(8, v.get_size());
|
||||
assert_eq!(0xaa000000, getUnsignedInt(&v));
|
||||
// 10101010 1
|
||||
v.appendBit(true);
|
||||
assert_eq!(9, v.getSize());
|
||||
assert_eq!(9, v.get_size());
|
||||
assert_eq!(0xaa800000, getUnsignedInt(&v));
|
||||
// 10101010 10
|
||||
v.appendBit(false);
|
||||
assert_eq!(10, v.getSize());
|
||||
assert_eq!(10, v.get_size());
|
||||
assert_eq!(0xaa800000, getUnsignedInt(&v));
|
||||
}
|
||||
|
||||
@@ -83,15 +83,15 @@ fn testAppendBit() {
|
||||
fn testAppendBits() {
|
||||
let mut v = BitArray::new();
|
||||
v.appendBits(0x1, 1).expect("append");
|
||||
assert_eq!(1, v.getSize());
|
||||
assert_eq!(1, v.get_size());
|
||||
assert_eq!(0x80000000, getUnsignedInt(&v));
|
||||
let mut v = BitArray::new();
|
||||
v.appendBits(0xff, 8).expect("append");
|
||||
assert_eq!(8, v.getSize());
|
||||
assert_eq!(8, v.get_size());
|
||||
assert_eq!(0xff000000, getUnsignedInt(&v));
|
||||
let mut v = BitArray::new();
|
||||
v.appendBits(0xff7, 12).expect("append");
|
||||
assert_eq!(12, v.getSize());
|
||||
assert_eq!(12, v.get_size());
|
||||
assert_eq!(0xff700000, getUnsignedInt(&v));
|
||||
}
|
||||
|
||||
|
||||
@@ -174,11 +174,11 @@ pub fn embedTypeInfo(
|
||||
for (i, coordinates) in TYPE_INFO_COORDINATES
|
||||
.iter()
|
||||
.enumerate()
|
||||
.take(typeInfoBits.getSize())
|
||||
.take(typeInfoBits.get_size())
|
||||
{
|
||||
// Place bits in LSB to MSB order. LSB (least significant bit) is the last value in
|
||||
// "typeInfoBits".
|
||||
let bit = typeInfoBits.get(typeInfoBits.getSize() - 1 - i);
|
||||
let bit = typeInfoBits.get(typeInfoBits.get_size() - 1 - i);
|
||||
|
||||
// Type info bits at the left top corner. See 8.9 of JISX0510:2004 (p.46).
|
||||
// let coordinates = TYPE_INFO_COORDINATES[i];
|
||||
@@ -249,7 +249,7 @@ pub fn embedDataBits(dataBits: &BitArray, maskPattern: i32, matrix: &mut ByteMat
|
||||
continue;
|
||||
}
|
||||
let mut bit;
|
||||
if bitIndex < dataBits.getSize() {
|
||||
if bitIndex < dataBits.get_size() {
|
||||
bit = dataBits.get(bitIndex);
|
||||
bitIndex += 1;
|
||||
} else {
|
||||
@@ -273,11 +273,11 @@ pub fn embedDataBits(dataBits: &BitArray, maskPattern: i32, matrix: &mut ByteMat
|
||||
x -= 2; // Move to the left.
|
||||
}
|
||||
// All bits should be consumed.
|
||||
if bitIndex != dataBits.getSize() {
|
||||
if bitIndex != dataBits.get_size() {
|
||||
return Err(Exceptions::writer_with(format!(
|
||||
"Not all bits consumed: {}/{}",
|
||||
bitIndex,
|
||||
dataBits.getSize()
|
||||
dataBits.get_size()
|
||||
)));
|
||||
}
|
||||
Ok(())
|
||||
@@ -355,11 +355,11 @@ pub fn makeTypeInfoBits(
|
||||
maskBits.appendBits(TYPE_INFO_MASK_PATTERN, 15)?;
|
||||
bits.xor(&maskBits)?;
|
||||
|
||||
if bits.getSize() != 15 {
|
||||
if bits.get_size() != 15 {
|
||||
// Just in case.
|
||||
return Err(Exceptions::writer_with(format!(
|
||||
"should not happen but we got: {}",
|
||||
bits.getSize()
|
||||
bits.get_size()
|
||||
)));
|
||||
}
|
||||
Ok(())
|
||||
@@ -372,11 +372,11 @@ pub fn makeVersionInfoBits(version: &Version, bits: &mut BitArray) -> Result<()>
|
||||
let bchCode = calculateBCHCode(version.getVersionNumber(), VERSION_INFO_POLY)?;
|
||||
bits.appendBits(bchCode, 12)?;
|
||||
|
||||
if bits.getSize() != 18 {
|
||||
if bits.get_size() != 18 {
|
||||
// Just in case.
|
||||
return Err(Exceptions::writer_with(format!(
|
||||
"should not happen but we got: {}",
|
||||
bits.getSize()
|
||||
bits.get_size()
|
||||
)));
|
||||
}
|
||||
Ok(())
|
||||
|
||||
@@ -846,7 +846,7 @@ impl RXingResultList {
|
||||
result
|
||||
}
|
||||
|
||||
fn internal_static_get_size(version: VersionRef, list: &Vec<RXingResultNode>) -> u32 {
|
||||
fn internal_static_get_size(version: VersionRef, list: &[RXingResultNode]) -> u32 {
|
||||
let result = list.iter().fold(0, |acc, node| acc + node.getSize(version));
|
||||
result
|
||||
}
|
||||
|
||||
@@ -286,7 +286,7 @@ fn calculateBitsNeeded(
|
||||
data_bits: &BitArray,
|
||||
version: VersionRef,
|
||||
) -> u32 {
|
||||
(header_bits.getSize() + mode.getCharacterCountBits(version) as usize + data_bits.getSize())
|
||||
(header_bits.get_size() + mode.getCharacterCountBits(version) as usize + data_bits.get_size())
|
||||
as u32
|
||||
}
|
||||
|
||||
@@ -413,21 +413,21 @@ pub fn willFit(numInputBits: u32, version: VersionRef, ecLevel: &ErrorCorrection
|
||||
*/
|
||||
pub fn terminateBits(num_data_bytes: u32, bits: &mut BitArray) -> Result<()> {
|
||||
let capacity = num_data_bytes * 8;
|
||||
if bits.getSize() > capacity as usize {
|
||||
if bits.get_size() > capacity as usize {
|
||||
return Err(Exceptions::writer_with(format!(
|
||||
"data bits cannot fit in the QR Code{capacity} > "
|
||||
)));
|
||||
}
|
||||
// Append Mode.TERMINATE if there is enough space (value is 0000)
|
||||
for _i in 0..4 {
|
||||
if bits.getSize() >= capacity as usize {
|
||||
if bits.get_size() >= capacity as usize {
|
||||
break;
|
||||
}
|
||||
bits.appendBit(false);
|
||||
}
|
||||
// Append termination bits. See 8.4.8 of JISX0510:2004 (p.24) for details.
|
||||
// If the last byte isn't 8-bit aligned, we'll add padding bits.
|
||||
let num_bits_in_last_byte = bits.getSize() & 0x07;
|
||||
let num_bits_in_last_byte = bits.get_size() & 0x07;
|
||||
if num_bits_in_last_byte > 0 {
|
||||
for _i in num_bits_in_last_byte..8 {
|
||||
bits.appendBit(false);
|
||||
@@ -441,7 +441,7 @@ pub fn terminateBits(num_data_bytes: u32, bits: &mut BitArray) -> Result<()> {
|
||||
}
|
||||
bits.appendBits(if (i & 0x01) == 0 { 0xEC } else { 0x11 }, 8)?;
|
||||
}
|
||||
if bits.getSize() != capacity as usize {
|
||||
if bits.get_size() != capacity as usize {
|
||||
return Err(Exceptions::writer_with("Bits size does not equal capacity"));
|
||||
}
|
||||
Ok(())
|
||||
|
||||
@@ -18,7 +18,7 @@ use std::collections::HashMap;
|
||||
|
||||
use crate::{
|
||||
common::{BitMatrix, DecoderRXingResult, DetectorRXingResult, Result},
|
||||
BarcodeFormat, DecodeHintType, DecodeHintValue, Exceptions, Point, RXingResult,
|
||||
BarcodeFormat, Binarizer, DecodeHintType, DecodeHintValue, Exceptions, Point, RXingResult,
|
||||
RXingResultMetadataType, RXingResultMetadataValue, Reader,
|
||||
};
|
||||
|
||||
@@ -48,27 +48,27 @@ impl Reader for QRCodeReader {
|
||||
* @throws FormatException if a QR code cannot be decoded
|
||||
* @throws ChecksumException if error correction fails
|
||||
*/
|
||||
fn decode(&mut self, image: &mut crate::BinaryBitmap) -> Result<crate::RXingResult> {
|
||||
fn decode<B: Binarizer>(&mut self, image: &mut crate::BinaryBitmap<B>) -> Result<RXingResult> {
|
||||
self.decode_with_hints(image, &HashMap::new())
|
||||
}
|
||||
|
||||
fn decode_with_hints(
|
||||
fn decode_with_hints<B: Binarizer>(
|
||||
&mut self,
|
||||
image: &mut crate::BinaryBitmap,
|
||||
image: &mut crate::BinaryBitmap<B>,
|
||||
hints: &crate::DecodingHintDictionary,
|
||||
) -> Result<crate::RXingResult> {
|
||||
) -> Result<RXingResult> {
|
||||
let decoderRXingResult: DecoderRXingResult;
|
||||
let mut points: Vec<Point>;
|
||||
if matches!(
|
||||
hints.get(&DecodeHintType::PURE_BARCODE),
|
||||
Some(DecodeHintValue::PureBarcode(true))
|
||||
) {
|
||||
let bits = Self::extractPureBits(image.getBlackMatrix())?;
|
||||
let bits = Self::extractPureBits(image.get_black_matrix())?;
|
||||
decoderRXingResult = qrcode_decoder::decode_bitmatrix_with_hints(&bits, hints)?;
|
||||
points = Vec::new();
|
||||
} else {
|
||||
let detectorRXingResult =
|
||||
Detector::new(image.getBlackMatrix()).detect_with_hints(hints)?;
|
||||
Detector::new(image.get_black_matrix()).detect_with_hints(hints)?;
|
||||
decoderRXingResult =
|
||||
qrcode_decoder::decode_bitmatrix_with_hints(detectorRXingResult.getBits(), hints)?;
|
||||
points = detectorRXingResult.getPoints().to_vec();
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
//package com.google.zxing;
|
||||
|
||||
use crate::{common::Result, BinaryBitmap, DecodingHintDictionary, RXingResult};
|
||||
use crate::{common::Result, Binarizer, BinaryBitmap, DecodingHintDictionary, RXingResult};
|
||||
|
||||
/**
|
||||
* Implementations of this interface can decode an image of a barcode in some format into
|
||||
@@ -40,7 +40,7 @@ pub trait Reader {
|
||||
* @throws ChecksumException if a potential barcode is found but does not pass its checksum
|
||||
* @throws FormatException if a potential barcode is found but format is invalid
|
||||
*/
|
||||
fn decode(&mut self, image: &mut BinaryBitmap) -> Result<RXingResult>;
|
||||
fn decode<B: Binarizer>(&mut self, image: &mut BinaryBitmap<B>) -> Result<RXingResult>;
|
||||
|
||||
/**
|
||||
* Locates and decodes a barcode in some format within an image. This method also accepts
|
||||
@@ -56,9 +56,9 @@ pub trait Reader {
|
||||
* @throws ChecksumException if a potential barcode is found but does not pass its checksum
|
||||
* @throws FormatException if a potential barcode is found but format is invalid
|
||||
*/
|
||||
fn decode_with_hints(
|
||||
fn decode_with_hints<B: Binarizer>(
|
||||
&mut self,
|
||||
image: &mut BinaryBitmap,
|
||||
image: &mut BinaryBitmap<B>,
|
||||
hints: &DecodingHintDictionary,
|
||||
) -> Result<RXingResult>;
|
||||
|
||||
|
||||
@@ -40,11 +40,11 @@ pub struct RGBLuminanceSource {
|
||||
|
||||
impl LuminanceSource for RGBLuminanceSource {
|
||||
/// gets a row, returns an empty row if we are out of bounds.
|
||||
fn getRow(&self, y: usize) -> Vec<u8> {
|
||||
if y >= self.getHeight() {
|
||||
fn get_row(&self, y: usize) -> Vec<u8> {
|
||||
if y >= self.get_height() {
|
||||
return Vec::new();
|
||||
}
|
||||
let width = self.getWidth();
|
||||
let width = self.get_width();
|
||||
|
||||
let offset = (y + self.top) * self.dataWidth + self.left;
|
||||
|
||||
@@ -58,9 +58,9 @@ impl LuminanceSource for RGBLuminanceSource {
|
||||
row
|
||||
}
|
||||
|
||||
fn getMatrix(&self) -> Vec<u8> {
|
||||
let width = self.getWidth();
|
||||
let height = self.getHeight();
|
||||
fn get_matrix(&self) -> Vec<u8> {
|
||||
let width = self.get_width();
|
||||
let height = self.get_height();
|
||||
|
||||
// If the caller asks for the entire underlying image, save the copy and give them the
|
||||
// original data. The docs specifically warn that result.length must be ignored.
|
||||
@@ -99,26 +99,20 @@ impl LuminanceSource for RGBLuminanceSource {
|
||||
matrix
|
||||
}
|
||||
|
||||
fn getWidth(&self) -> usize {
|
||||
fn get_width(&self) -> usize {
|
||||
self.width
|
||||
}
|
||||
|
||||
fn getHeight(&self) -> usize {
|
||||
fn get_height(&self) -> usize {
|
||||
self.height
|
||||
}
|
||||
|
||||
fn isCropSupported(&self) -> bool {
|
||||
fn is_crop_supported(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn crop(
|
||||
&self,
|
||||
left: usize,
|
||||
top: usize,
|
||||
width: usize,
|
||||
height: usize,
|
||||
) -> Result<Box<dyn LuminanceSource>> {
|
||||
match RGBLuminanceSource::new_complex(
|
||||
fn crop(&self, left: usize, top: usize, width: usize, height: usize) -> Result<Self> {
|
||||
RGBLuminanceSource::new_complex(
|
||||
&self.luminances,
|
||||
self.dataWidth,
|
||||
self.dataHeight,
|
||||
@@ -126,10 +120,8 @@ impl LuminanceSource for RGBLuminanceSource {
|
||||
self.top + top,
|
||||
width,
|
||||
height,
|
||||
) {
|
||||
Ok(crop) => Ok(Box::new(crop)),
|
||||
Err(_error) => Err(Exceptions::UNSUPPORTED_OPERATION),
|
||||
}
|
||||
)
|
||||
.map_err(|_| Exceptions::UNSUPPORTED_OPERATION)
|
||||
}
|
||||
|
||||
fn invert(&mut self) {
|
||||
|
||||
@@ -34,11 +34,11 @@ const SRC_DATA: [u32; 9] = [
|
||||
fn testCrop() {
|
||||
let SOURCE = RGBLuminanceSource::new_with_width_height_pixels(3, 3, SRC_DATA.as_ref());
|
||||
|
||||
assert!(SOURCE.isCropSupported());
|
||||
assert!(SOURCE.is_crop_supported());
|
||||
let cropped = SOURCE.crop(1, 1, 1, 1).unwrap();
|
||||
assert_eq!(1, cropped.getHeight());
|
||||
assert_eq!(1, cropped.getWidth());
|
||||
assert_eq!(vec![0x7F], cropped.getRow(0));
|
||||
assert_eq!(1, cropped.get_height());
|
||||
assert_eq!(1, cropped.get_width());
|
||||
assert_eq!(vec![0x7F], cropped.get_row(0));
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -47,22 +47,22 @@ fn testMatrix() {
|
||||
|
||||
assert_eq!(
|
||||
vec![0x00, 0x7F, 0xFF, 0x3F, 0x7F, 0x3F, 0x3F, 0x7F, 0x3F],
|
||||
SOURCE.getMatrix()
|
||||
SOURCE.get_matrix()
|
||||
);
|
||||
let croppedFullWidth = SOURCE.crop(0, 1, 3, 2).unwrap();
|
||||
assert_eq!(
|
||||
vec![0x3F, 0x7F, 0x3F, 0x3F, 0x7F, 0x3F],
|
||||
croppedFullWidth.getMatrix()
|
||||
croppedFullWidth.get_matrix()
|
||||
);
|
||||
let croppedCorner = SOURCE.crop(1, 1, 2, 2).unwrap();
|
||||
assert_eq!(vec![0x7F, 0x3F, 0x7F, 0x3F], croppedCorner.getMatrix());
|
||||
assert_eq!(vec![0x7F, 0x3F, 0x7F, 0x3F], croppedCorner.get_matrix());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn testGetRow() {
|
||||
let SOURCE = RGBLuminanceSource::new_with_width_height_pixels(3, 3, SRC_DATA.as_ref());
|
||||
|
||||
assert_eq!(vec![0x3F, 0x7F, 0x3F], SOURCE.getRow(2));
|
||||
assert_eq!(vec![0x3F, 0x7F, 0x3F], SOURCE.get_row(2));
|
||||
}
|
||||
|
||||
// #[test]
|
||||
|
||||
@@ -6,50 +6,44 @@ use resvg::{self, usvg::Options};
|
||||
pub struct SVGLuminanceSource(BufferedImageLuminanceSource);
|
||||
|
||||
impl LuminanceSource for SVGLuminanceSource {
|
||||
fn getRow(&self, y: usize) -> Vec<u8> {
|
||||
self.0.getRow(y)
|
||||
fn get_row(&self, y: usize) -> Vec<u8> {
|
||||
self.0.get_row(y)
|
||||
}
|
||||
|
||||
fn getMatrix(&self) -> Vec<u8> {
|
||||
self.0.getMatrix()
|
||||
fn get_matrix(&self) -> Vec<u8> {
|
||||
self.0.get_matrix()
|
||||
}
|
||||
|
||||
fn getWidth(&self) -> usize {
|
||||
self.0.getWidth()
|
||||
fn get_width(&self) -> usize {
|
||||
self.0.get_width()
|
||||
}
|
||||
|
||||
fn getHeight(&self) -> usize {
|
||||
self.0.getHeight()
|
||||
fn get_height(&self) -> usize {
|
||||
self.0.get_height()
|
||||
}
|
||||
|
||||
fn is_crop_supported(&self) -> bool {
|
||||
self.0.is_crop_supported()
|
||||
}
|
||||
|
||||
fn crop(&self, left: usize, top: usize, width: usize, height: usize) -> Result<Self> {
|
||||
self.0.crop(left, top, width, height).map(Self)
|
||||
}
|
||||
|
||||
fn is_rotate_supported(&self) -> bool {
|
||||
self.0.is_rotate_supported()
|
||||
}
|
||||
|
||||
fn invert(&mut self) {
|
||||
self.0.invert()
|
||||
}
|
||||
|
||||
fn isCropSupported(&self) -> bool {
|
||||
self.0.isCropSupported()
|
||||
fn rotate_counter_clockwise(&self) -> Result<Self> {
|
||||
self.0.rotate_counter_clockwise().map(Self)
|
||||
}
|
||||
|
||||
fn crop(
|
||||
&self,
|
||||
left: usize,
|
||||
top: usize,
|
||||
width: usize,
|
||||
height: usize,
|
||||
) -> Result<Box<dyn LuminanceSource>> {
|
||||
self.0.crop(left, top, width, height)
|
||||
}
|
||||
|
||||
fn isRotateSupported(&self) -> bool {
|
||||
self.0.isRotateSupported()
|
||||
}
|
||||
|
||||
fn rotateCounterClockwise(&self) -> Result<Box<dyn LuminanceSource>> {
|
||||
self.0.rotateCounterClockwise()
|
||||
}
|
||||
|
||||
fn rotateCounterClockwise45(&self) -> Result<Box<dyn LuminanceSource>> {
|
||||
self.0.rotateCounterClockwise45()
|
||||
fn rotate_counter_clockwise_45(&self) -> Result<Self> {
|
||||
self.0.rotate_counter_clockwise_45().map(Self)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -28,8 +28,8 @@ use encoding::Encoding;
|
||||
use rxing::{
|
||||
common::{HybridBinarizer, Result},
|
||||
pdf417::PDF417RXingResultMetadata,
|
||||
BarcodeFormat, BinaryBitmap, BufferedImageLuminanceSource, DecodeHintType, DecodeHintValue,
|
||||
RXingResultMetadataType, RXingResultMetadataValue, Reader,
|
||||
BarcodeFormat, Binarizer, BinaryBitmap, BufferedImageLuminanceSource, DecodeHintType,
|
||||
DecodeHintValue, RXingResultMetadataType, RXingResultMetadataValue, Reader,
|
||||
};
|
||||
|
||||
use super::TestRXingResult;
|
||||
@@ -251,7 +251,7 @@ impl<T: Reader> AbstractBlackBoxTestCase<T> {
|
||||
let rotation = self.test_rxing_results.get(x).unwrap().get_rotation();
|
||||
let rotated_image = Self::rotate_image(&image, rotation);
|
||||
let source = BufferedImageLuminanceSource::new(rotated_image);
|
||||
let mut bitmap = BinaryBitmap::new(Rc::new(HybridBinarizer::new(Box::new(source))));
|
||||
let mut bitmap = BinaryBitmap::new(HybridBinarizer::new(source));
|
||||
|
||||
// if file_base_name == "15" {
|
||||
// let mut f = File::create("test_file_output.txt").unwrap();
|
||||
@@ -259,21 +259,23 @@ impl<T: Reader> AbstractBlackBoxTestCase<T> {
|
||||
// drop(f);
|
||||
// Self::rotate_image(&image, rotation).save("test_image.png").unwrap();
|
||||
// }
|
||||
|
||||
if let Ok(decoded) = self.decode(
|
||||
match self.decode(
|
||||
&mut bitmap,
|
||||
rotation,
|
||||
&expected_text,
|
||||
&expected_metadata,
|
||||
false,
|
||||
) {
|
||||
if decoded {
|
||||
passed_counts[x] += 1;
|
||||
} else {
|
||||
misread_counts[x] += 1;
|
||||
Ok(decoded) => {
|
||||
if decoded {
|
||||
passed_counts[x] += 1;
|
||||
} else {
|
||||
misread_counts[x] += 1;
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
log::fine(format!("could not read at rotation {rotation}: {e:?}"));
|
||||
}
|
||||
} else {
|
||||
log::fine(format!("could not read at rotation {rotation}"));
|
||||
}
|
||||
// try {
|
||||
// if (decode(bitmap, rotation, expectedText, expectedMetadata, false)) {
|
||||
@@ -284,20 +286,23 @@ impl<T: Reader> AbstractBlackBoxTestCase<T> {
|
||||
// } catch (ReaderException ignored) {
|
||||
// log::fine(format!("could not read at rotation {}", rotation));
|
||||
// }
|
||||
if let Ok(decoded) = self.decode(
|
||||
match self.decode(
|
||||
&mut bitmap,
|
||||
rotation,
|
||||
&expected_text,
|
||||
&expected_metadata,
|
||||
true,
|
||||
) {
|
||||
if decoded {
|
||||
try_harder_counts[x] += 1;
|
||||
} else {
|
||||
try_harder_misread_counts[x] += 1;
|
||||
Ok(decoded) => {
|
||||
if decoded {
|
||||
try_harder_counts[x] += 1;
|
||||
} else {
|
||||
try_harder_misread_counts[x] += 1;
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
log::fine(format!("could not read at rotation {rotation} w/TH: {e:?}"));
|
||||
}
|
||||
} else {
|
||||
log::fine(format!("could not read at rotation {rotation} w/TH"));
|
||||
}
|
||||
// try {
|
||||
// if (decode(bitmap, rotation, expectedText, expectedMetadata, true)) {
|
||||
@@ -422,9 +427,9 @@ impl<T: Reader> AbstractBlackBoxTestCase<T> {
|
||||
}
|
||||
}
|
||||
|
||||
fn decode(
|
||||
fn decode<B: Binarizer>(
|
||||
&mut self,
|
||||
source: &mut BinaryBitmap,
|
||||
source: &mut BinaryBitmap<B>,
|
||||
rotation: f32,
|
||||
expected_text: &str,
|
||||
expected_metadata: &HashMap<RXingResultMetadataType, RXingResultMetadataValue>,
|
||||
|
||||
@@ -28,8 +28,8 @@ use rxing::{
|
||||
common::{HybridBinarizer, Result},
|
||||
multi::MultipleBarcodeReader,
|
||||
pdf417::PDF417RXingResultMetadata,
|
||||
BarcodeFormat, BinaryBitmap, BufferedImageLuminanceSource, DecodeHintType, DecodeHintValue,
|
||||
RXingResult, RXingResultMetadataType, RXingResultMetadataValue, Reader,
|
||||
BarcodeFormat, Binarizer, BinaryBitmap, BufferedImageLuminanceSource, DecodeHintType,
|
||||
DecodeHintValue, RXingResult, RXingResultMetadataType, RXingResultMetadataValue, Reader,
|
||||
};
|
||||
|
||||
use super::TestRXingResult;
|
||||
@@ -180,8 +180,7 @@ impl<T: MultipleBarcodeReader + Reader> PDF417MultiImageSpanAbstractBlackBoxTest
|
||||
let rotation: f32 = self.test_rxing_results.get(x).expect("ok").get_rotation();
|
||||
let rotated_image = Self::rotate_image(&image, rotation);
|
||||
let source = BufferedImageLuminanceSource::new(rotated_image);
|
||||
let mut bitmap =
|
||||
BinaryBitmap::new(Rc::new(HybridBinarizer::new(Box::new(source))));
|
||||
let mut bitmap = BinaryBitmap::new(HybridBinarizer::new(source));
|
||||
|
||||
if let Ok(res) =
|
||||
Self::decode_pdf417(&mut bitmap, false, &mut self.barcode_reader)
|
||||
@@ -395,7 +394,7 @@ impl<T: MultipleBarcodeReader + Reader> PDF417MultiImageSpanAbstractBlackBoxTest
|
||||
let rotation = self.test_rxing_results.get(x).unwrap().get_rotation();
|
||||
let rotated_image = Self::rotate_image(&image, rotation);
|
||||
let source = BufferedImageLuminanceSource::new(rotated_image);
|
||||
let mut bitmap = BinaryBitmap::new(Rc::new(HybridBinarizer::new(Box::new(source))));
|
||||
let mut bitmap = BinaryBitmap::new(HybridBinarizer::new(source));
|
||||
|
||||
// if file_base_name == "15" {
|
||||
// let mut f = File::create("test_file_output.txt").unwrap();
|
||||
@@ -566,9 +565,9 @@ impl<T: MultipleBarcodeReader + Reader> PDF417MultiImageSpanAbstractBlackBoxTest
|
||||
}
|
||||
}
|
||||
|
||||
fn decode(
|
||||
fn decode<B: Binarizer>(
|
||||
&mut self,
|
||||
source: &mut BinaryBitmap,
|
||||
source: &mut BinaryBitmap<B>,
|
||||
rotation: f32,
|
||||
expected_text: &str,
|
||||
expected_metadata: &HashMap<RXingResultMetadataType, RXingResultMetadataValue>,
|
||||
@@ -754,8 +753,8 @@ impl<T: MultipleBarcodeReader + Reader> PDF417MultiImageSpanAbstractBlackBoxTest
|
||||
}
|
||||
}
|
||||
|
||||
fn decode_pdf417(
|
||||
source: &mut BinaryBitmap,
|
||||
fn decode_pdf417<B: Binarizer>(
|
||||
source: &mut BinaryBitmap<B>,
|
||||
try_harder: bool,
|
||||
barcode_reader: &mut T,
|
||||
) -> Result<Vec<RXingResult>> {
|
||||
|
||||
Reference in New Issue
Block a user