Initial generics

This commit is contained in:
Steve Cook
2023-03-01 22:08:12 -05:00
parent 26325928e7
commit a9bc58108c
65 changed files with 1013 additions and 883 deletions

View File

@@ -23,27 +23,28 @@ fn impl_one_d_reader_macro(ast: &syn::DeriveInput) -> TokenStream {
use crate::RXingResultMetadataValue; use crate::RXingResultMetadataValue;
use crate::RXingResultPoint; use crate::RXingResultPoint;
use crate::Reader; use crate::Reader;
use crate::Binarizer;
impl Reader for #name { 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()) self.decode_with_hints(image, &HashMap::new())
} }
// Note that we don't try rotation without the try harder flag, even if rotation was supported. // 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, &mut self,
image: &mut crate::BinaryBitmap, image: &mut crate::BinaryBitmap<B>,
hints: &DecodingHintDictionary, hints: &DecodingHintDictionary,
) -> Result<crate::RXingResult, Exceptions> { ) -> Result<crate::RXingResult, Exceptions> {
if let Ok(res) = self.doDecode(image, hints) { if let Ok(res) = self._do_decode(image, hints) {
Ok(res) Ok(res)
}else { }else {
let tryHarder = hints.contains_key(&DecodeHintType::TRY_HARDER); let tryHarder = hints.contains_key(&DecodeHintType::TRY_HARDER);
if tryHarder && image.isRotateSupported() { if tryHarder && image.is_rotate_supported() {
let mut rotatedImage = image.rotateCounterClockwise(); let mut rotated_image = image.rotate_counter_clockwise();
let mut result = self.doDecode(&mut rotatedImage, hints)?; let mut result = self._do_decode(&mut rotated_image, hints)?;
// Record that we found it rotated 90 degrees CCW / 270 degrees CW // Record that we found it rotated 90 degrees CCW / 270 degrees CW
let metadata = result.getRXingResultMetadata(); let metadata = result.getRXingResultMetadata();
let mut orientation = 270; let mut orientation = 270;
if metadata.contains_key(&RXingResultMetadataType::ORIENTATION) { if metadata.contains_key(&RXingResultMetadataType::ORIENTATION) {
// But if we found it reversed in doDecode(), add in that result here: // But if we found it reversed in doDecode(), add in that result here:
@@ -58,7 +59,7 @@ fn impl_one_d_reader_macro(ast: &syn::DeriveInput) -> TokenStream {
// Update result points // Update result points
// let points = result.getRXingResultPoints(); // let points = result.getRXingResultPoints();
// if points != null { // if points != null {
let height = rotatedImage.getHeight(); let height = rotated_image.get_height();
// for point in result.getRXingResultPointsMut().iter_mut() { // for point in result.getRXingResultPointsMut().iter_mut() {
let total_points = result.getRXingResultPoints().len(); let total_points = result.getRXingResultPoints().len();
let points = result.getRXingResultPointsMut(); let points = result.getRXingResultPointsMut();
@@ -93,13 +94,13 @@ fn impl_ean_reader_macro(ast: &syn::DeriveInput) -> TokenStream {
let name = &ast.ident; let name = &ast.ident;
let gen = quote! { let gen = quote! {
impl super::OneDReader for #name { impl super::OneDReader for #name {
fn decodeRow( fn decode_row(
&mut self, &mut self,
rowNumber: u32, rowNumber: u32,
row: &crate::common::BitArray, row: &crate::common::BitArray,
hints: &crate::DecodingHintDictionary, hints: &crate::DecodingHintDictionary,
) -> Result<crate::RXingResult, crate::Exceptions> { ) -> Result<crate::RXingResult, crate::Exceptions> {
self.decodeRowWithGuardRange(rowNumber, row, &self.findStartGuardPattern(row)?, hints) self.decodeRowWithGuardRange(rowNumber, row, &self.find_start_guard_pattern(row)?, hints)
} }
} }
}; };

View File

@@ -52,10 +52,10 @@ fn test_no_crop() {
false, false,
) )
.unwrap(); .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 r in 0..ROWS {
// for (int r = 0; r < ROWS; r++) { // 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, false,
) )
.unwrap(); .unwrap();
assert!(source.isCropSupported()); assert!(source.is_crop_supported());
let cropMatrix = source.getMatrix(); let cropMatrix = source.get_matrix();
for r in 0..ROWS - 2 { for r in 0..ROWS - 2 {
// for (int r = 0; r < ROWS - 2; r++) { // for (int r = 0; r < ROWS - 2; r++) {
assert_equals( assert_equals(
@@ -87,7 +87,7 @@ fn test_crop() {
} }
for r in 0..ROWS - 2 { for r in 0..ROWS - 2 {
// for (int r = 0; r < ROWS - 2; r++) { // 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);
} }
} }

View File

@@ -19,7 +19,7 @@ use std::collections::HashMap;
use crate::{ use crate::{
common::{DecoderRXingResult, DetectorRXingResult, Result}, common::{DecoderRXingResult, DetectorRXingResult, Result},
exceptions::Exceptions, exceptions::Exceptions,
BarcodeFormat, BinaryBitmap, DecodeHintType, DecodeHintValue, RXingResult, BarcodeFormat, Binarizer, BinaryBitmap, DecodeHintType, DecodeHintValue, RXingResult,
RXingResultMetadataType, RXingResultMetadataValue, Reader, RXingResultMetadataType, RXingResultMetadataValue, Reader,
}; };
@@ -41,18 +41,18 @@ impl Reader for AztecReader {
* @throws NotFoundException if a Data Matrix code cannot be found * @throws NotFoundException if a Data Matrix code cannot be found
* @throws FormatException if a Data Matrix code cannot be decoded * @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()) self.decode_with_hints(image, &HashMap::new())
} }
fn decode_with_hints( fn decode_with_hints<B: Binarizer>(
&mut self, &mut self,
image: &mut BinaryBitmap, image: &mut BinaryBitmap<B>,
hints: &HashMap<DecodeHintType, DecodeHintValue>, hints: &HashMap<DecodeHintType, DecodeHintValue>,
) -> Result<RXingResult> { ) -> Result<RXingResult> {
// let notFoundException = None; // let notFoundException = None;
// let formatException = None; // let formatException = None;
let mut detector = Detector::new(image.getBlackMatrix()); let mut detector = Detector::new(image.get_black_matrix());
// try { // try {

View File

@@ -157,8 +157,8 @@ pub fn encode_bytes_with_charset(
let bits = HighLevelEncoder::with_charset(data.into(), charset).encode()?; let bits = HighLevelEncoder::with_charset(data.into(), charset).encode()?;
// stuff bits and choose symbol size // stuff bits and choose symbol size
let ecc_bits = bits.getSize() as u32 * min_eccpercent / 100 + 11; let ecc_bits = bits.get_size() as u32 * min_eccpercent / 100 + 11;
let total_size_bits = bits.getSize() as u32 + ecc_bits; let total_size_bits = bits.get_size() as u32 + ecc_bits;
let mut compact; let mut compact;
let mut layers: u32; let mut layers: u32;
let mut total_bits_in_layer_var; let mut total_bits_in_layer_var;
@@ -182,12 +182,12 @@ pub fn encode_bytes_with_charset(
word_size = WORD_SIZE[layers as usize]; word_size = WORD_SIZE[layers as usize];
let usable_bits_in_layers = total_bits_in_layer_var - (total_bits_in_layer_var % word_size); 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)?; 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( return Err(Exceptions::illegal_argument_with(
"Data to large for user specified layer", "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 // Compact format only allows 64 data words, though C4 can hold more words than that
return Err(Exceptions::illegal_argument_with( return Err(Exceptions::illegal_argument_with(
"Data to large for user specified layer", "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 // [Re]stuff the bits if this is the first opportunity, or if the
// wordSize has changed // 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]; word_size = WORD_SIZE[layers as usize];
stuffed_bits = stuffBits(&bits, word_size as usize)?; stuffed_bits = stuffBits(&bits, word_size as usize)?;
} }
let usable_bits_in_layers = let usable_bits_in_layers =
total_bits_in_layer_var - (total_bits_in_layer_var % word_size); 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 // Compact format only allows 64 data words, though C4 can hold more words than that
i += 1; i += 1;
continue; 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; break;
} }
i += 1; i += 1;
@@ -240,7 +240,7 @@ pub fn encode_bytes_with_charset(
)?; )?;
// generate mode message // 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)?; let modeMessage = generateModeMessage(compact, layers, messageSizeInWords)?;
// allocate symbol // 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> { fn generateCheckWords(bitArray: &BitArray, totalBits: usize, wordSize: usize) -> Result<BitArray> {
// bitArray is guaranteed to be a multiple of the wordSize, so no padding needed // 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 mut rs = ReedSolomonEncoder::new(getGF(wordSize)?)?;
let total_words = totalBits / wordSize; let total_words = totalBits / wordSize;
let mut message_words = bitsToWords(bitArray, wordSize, total_words); 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> { fn bitsToWords(stuffedBits: &BitArray, wordSize: usize, totalWords: usize) -> Vec<i32> {
let mut message = vec![0; totalWords]; let mut message = vec![0; totalWords];
let mut i = 0; let mut i = 0;
let n = stuffedBits.getSize() / wordSize; let n = stuffedBits.get_size() / wordSize;
while i < n { while i < n {
// for (i = 0, n = stuffedBits.getSize() / wordSize; i < n; i++) { // for (i = 0, n = stuffedBits.getSize() / wordSize; i < n; i++) {
let mut value = 0; let mut value = 0;
@@ -483,7 +483,7 @@ fn getGF(wordSize: usize) -> Result<GenericGFRef> {
pub fn stuffBits(bits: &BitArray, word_size: usize) -> Result<BitArray> { pub fn stuffBits(bits: &BitArray, word_size: usize) -> Result<BitArray> {
let mut out = BitArray::new(); 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 mask = (1 << word_size) - 2;
let mut i: isize = 0; let mut i: isize = 0;
while i < n { while i < n {

View File

@@ -21,7 +21,7 @@ pub fn toBitArray(bits: &str) -> BitArray {
#[allow(dead_code)] #[allow(dead_code)]
pub fn toBooleanArray(bitArray: &BitArray) -> Vec<bool> { 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 in 0..result.len() {
for (i, res) in result.iter_mut().enumerate() { for (i, res) in result.iter_mut().enumerate() {
// for (int i = 0; i < result.length; i++) { // for (int i = 0; i < result.length; i++) {

View File

@@ -16,7 +16,7 @@
//package com.google.zxing; //package com.google.zxing;
use std::{borrow::Cow, rc::Rc}; use std::borrow::Cow;
use crate::{ use crate::{
common::{BitArray, BitMatrix, Result}, common::{BitArray, BitMatrix, Result},
@@ -35,7 +35,9 @@ pub trait Binarizer {
//private final LuminanceSource source; //private final LuminanceSource source;
//fn new(source:dyn LuminanceSource) -> Self; //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 * 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). * @return The array of bits for this row (true means black).
* @throws NotFoundException if row can't be binarized * @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 * 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). * @return The 2D array of bits for the image (true means black).
* @throws NotFoundException if image can't be binarized to make a matrix * @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 * 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. * @param source The LuminanceSource this Binarizer will operate on.
* @return A new concrete Binarizer implementation object. * @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;
} }

View File

@@ -16,11 +16,11 @@
//package com.google.zxing; //package com.google.zxing;
use std::{borrow::Cow, fmt, rc::Rc}; use std::{borrow::Cow, fmt};
use crate::{ use crate::{
common::{BitArray, BitMatrix, Result}, common::{BitArray, BitMatrix, Result},
Binarizer, Binarizer, LuminanceSource,
}; };
/** /**
@@ -30,13 +30,13 @@ use crate::{
* @author dswitkin@google.com (Daniel Switkin) * @author dswitkin@google.com (Daniel Switkin)
*/ */
pub struct BinaryBitmap { pub struct BinaryBitmap<B: Binarizer> {
binarizer: Rc<dyn Binarizer>, binarizer: B,
matrix: Option<BitMatrix>, matrix: Option<BitMatrix>,
} }
impl BinaryBitmap { impl<B: Binarizer> BinaryBitmap<B> {
pub fn new(binarizer: Rc<dyn Binarizer>) -> Self { pub fn new(binarizer: B) -> Self {
Self { Self {
matrix: None, matrix: None,
binarizer, binarizer,
@@ -46,15 +46,15 @@ impl BinaryBitmap {
/** /**
* @return The width of the bitmap. * @return The width of the bitmap.
*/ */
pub fn getWidth(&self) -> usize { pub fn get_width(&self) -> usize {
self.binarizer.getWidth() self.binarizer.get_width()
} }
/** /**
* @return The height of the bitmap. * @return The height of the bitmap.
*/ */
pub fn getHeight(&self) -> usize { pub fn get_height(&self) -> usize {
self.binarizer.getHeight() self.binarizer.get_height()
} }
/** /**
@@ -68,8 +68,8 @@ impl BinaryBitmap {
* @return The array of bits for this row (true means black). * @return The array of bits for this row (true means black).
* @throws NotFoundException if row can't be binarized * @throws NotFoundException if row can't be binarized
*/ */
pub fn getBlackRow(&self, y: usize) -> Result<Cow<BitArray>> { pub fn get_black_row(&self, y: usize) -> Result<Cow<BitArray>> {
self.binarizer.getBlackRow(y) self.binarizer.get_black_row(y)
} }
/** /**
@@ -83,14 +83,14 @@ impl BinaryBitmap {
* @return The 2D array of bits for the image (true means black). * @return The 2D array of bits for the image (true means black).
* @throws NotFoundException if image can't be binarized to make a matrix * @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 // The matrix is created on demand the first time it is requested, then cached. There are two
// reasons for this: // reasons for this:
// 1. This work will never be done if the caller only installs 1D Reader objects, or if a // 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. // 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. // 2. This work will only be done once even if the caller installs multiple 2D Readers.
if self.matrix.is_none() { 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() self.matrix.as_mut().unwrap()
} }
@@ -106,14 +106,14 @@ impl BinaryBitmap {
* @return The 2D array of bits for the image (true means black). * @return The 2D array of bits for the image (true means black).
* @throws NotFoundException if image can't be binarized to make a matrix * @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 // The matrix is created on demand the first time it is requested, then cached. There are two
// reasons for this: // reasons for this:
// 1. This work will never be done if the caller only installs 1D Reader objects, or if a // 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. // 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. // 2. This work will only be done once even if the caller installs multiple 2D Readers.
if self.matrix.is_none() { 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() self.matrix.as_ref().unwrap()
} }
@@ -121,8 +121,8 @@ impl BinaryBitmap {
/** /**
* @return Whether this bitmap can be cropped. * @return Whether this bitmap can be cropped.
*/ */
pub fn isCropSupported(&self) -> bool { pub fn is_crop_supported(&self) -> bool {
self.binarizer.getLuminanceSource().isCropSupported() self.binarizer.get_luminance_source().is_crop_supported()
} }
/** /**
@@ -137,22 +137,22 @@ impl BinaryBitmap {
* @param height The height of the rectangle to crop. * @param height The height of the rectangle to crop.
* @return A cropped version of this object. * @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 let newSource = self
.binarizer .binarizer
.getLuminanceSource() .get_luminance_source()
.crop(left, top, width, height); .crop(left, top, width, height);
return BinaryBitmap::new( return BinaryBitmap::new(
self.binarizer 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. * @return Whether this bitmap supports counter-clockwise rotation.
*/ */
pub fn isRotateSupported(&self) -> bool { pub fn is_rotate_supported(&self) -> bool {
return self.binarizer.getLuminanceSource().isRotateSupported(); return self.binarizer.get_luminance_source().is_rotate_supported();
} }
/** /**
@@ -163,11 +163,14 @@ impl BinaryBitmap {
* *
* @return A rotated version of this object. * @return A rotated version of this object.
*/ */
pub fn rotateCounterClockwise(&mut self) -> BinaryBitmap { pub fn rotate_counter_clockwise(&mut self) -> Self {
let newSource = self.binarizer.getLuminanceSource().rotateCounterClockwise(); let newSource = self
.binarizer
.get_luminance_source()
.rotate_counter_clockwise();
return BinaryBitmap::new( return BinaryBitmap::new(
self.binarizer 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. * @return A rotated version of this object.
*/ */
pub fn rotateCounterClockwise45(&self) -> BinaryBitmap { pub fn rotate_counter_clockwise_45(&self) -> Self {
let newSource = self let newSource = self
.binarizer .binarizer
.getLuminanceSource() .get_luminance_source()
.rotateCounterClockwise45(); .rotate_counter_clockwise_45();
return BinaryBitmap::new( return BinaryBitmap::new(
self.binarizer 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 { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{:?}", self.matrix) write!(f, "{:?}", self.matrix)
} }

View File

@@ -88,8 +88,8 @@ impl BufferedImageLuminanceSource {
} }
impl LuminanceSource for BufferedImageLuminanceSource { impl LuminanceSource for BufferedImageLuminanceSource {
fn getRow(&self, y: usize) -> Vec<u8> { fn get_row(&self, y: usize) -> Vec<u8> {
let width = self.getWidth(); // - self.left as usize; let width = self.get_width(); // - self.left as usize;
let pixels: Vec<u8> = || -> Option<Vec<u8>> { let pixels: Vec<u8> = || -> Option<Vec<u8>> {
Some( Some(
@@ -108,7 +108,7 @@ impl LuminanceSource for BufferedImageLuminanceSource {
pixels 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 if self.height == self.image.height() as usize && self.width == self.image.width() as usize
{ {
return self.image.as_bytes().to_vec(); return self.image.as_bytes().to_vec();
@@ -141,56 +141,50 @@ impl LuminanceSource for BufferedImageLuminanceSource {
data data
} }
fn getWidth(&self) -> usize { fn get_width(&self) -> usize {
self.width self.width
} }
fn getHeight(&self) -> usize { fn get_height(&self) -> usize {
self.height 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) { fn invert(&mut self) {
let mut img = (*self.image).clone(); let mut img = (*self.image).clone();
img.invert(); img.invert();
self.image = Rc::new(img); self.image = Rc::new(img);
} }
fn isCropSupported(&self) -> bool { fn rotate_counter_clockwise(&self) -> Result<Self> {
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>> {
let img = self.image.rotate270(); let img = self.image.rotate270();
Ok(Box::new(Self { Ok(Self {
width: img.width() as usize, width: img.width() as usize,
height: img.height() as usize, height: img.height() as usize,
image: Rc::new(img), image: Rc::new(img),
left: 0, left: 0,
top: 0, top: 0,
})) })
} }
fn rotateCounterClockwise45(&self) -> Result<Box<dyn LuminanceSource>> { fn rotate_counter_clockwise_45(&self) -> Result<Self> {
let img = rotate_about_center( let img = rotate_about_center(
&self.image.to_luma8(), &self.image.to_luma8(),
MINUS_45_IN_RADIANS, MINUS_45_IN_RADIANS,
@@ -200,12 +194,12 @@ impl LuminanceSource for BufferedImageLuminanceSource {
let new_img = DynamicImage::from(img); let new_img = DynamicImage::from(img);
Ok(Box::new(Self { Ok(Self {
width: new_img.width() as usize, width: new_img.width() as usize,
height: new_img.height() as usize, height: new_img.height() as usize,
image: Rc::new(new_img), image: Rc::new(new_img),
left: 0, left: 0,
top: 0, top: 0,
})) })
} }
} }

View File

@@ -43,12 +43,12 @@ fn test_get_set() {
#[test] #[test]
fn test_get_next_set1() { fn test_get_next_set1() {
let array = BitArray::with_size(32); 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++) { // for (int i = 0; i < array.getSize(); i++) {
assert_eq!(32, array.getNextSet(i), "{i}"); assert_eq!(32, array.getNextSet(i), "{i}");
} }
let array = BitArray::with_size(33); 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++) { // for (int i = 0; i < array.getSize(); i++) {
assert_eq!(33, array.getNextSet(i), "{i}"); assert_eq!(33, array.getNextSet(i), "{i}");
} }
@@ -58,13 +58,13 @@ fn test_get_next_set1() {
fn test_get_next_set2() { fn test_get_next_set2() {
let mut array = BitArray::with_size(33); let mut array = BitArray::with_size(33);
array.set(31); array.set(31);
for i in 0..array.getSize() { for i in 0..array.get_size() {
// for (int i = 0; i < array.getSize(); i++) { // for (int i = 0; i < array.getSize(); i++) {
assert_eq!(if i <= 31 { 31 } else { 33 }, array.getNextSet(i), "{i}"); assert_eq!(if i <= 31 { 31 } else { 33 }, array.getNextSet(i), "{i}");
} }
array = BitArray::with_size(33); array = BitArray::with_size(33);
array.set(32); array.set(32);
for i in 0..array.getSize() { for i in 0..array.get_size() {
// for (int i = 0; i < array.getSize(); i++) { // for (int i = 0; i < array.getSize(); i++) {
assert_eq!(32, array.getNextSet(i), "{i}"); assert_eq!(32, array.getNextSet(i), "{i}");
} }
@@ -75,7 +75,7 @@ fn test_get_next_set3() {
let mut array = BitArray::with_size(63); let mut array = BitArray::with_size(63);
array.set(31); array.set(31);
array.set(32); array.set(32);
for i in 0..array.getSize() { for i in 0..array.get_size() {
// for (int i = 0; i < array.getSize(); i++) { // for (int i = 0; i < array.getSize(); i++) {
let expected; let expected;
if i <= 31 { if i <= 31 {
@@ -94,7 +94,7 @@ fn test_get_next_set4() {
let mut array = BitArray::with_size(63); let mut array = BitArray::with_size(63);
array.set(33); array.set(33);
array.set(40); array.set(40);
for i in 0..array.getSize() { for i in 0..array.get_size() {
// for (int i = 0; i < array.getSize(); i++) { // for (int i = 0; i < array.getSize(); i++) {
let expected; let expected;
if i <= 33 { if i <= 33 {
@@ -117,14 +117,14 @@ fn test_get_next_set5() {
let numSet = r.gen_range(0..20); let numSet = r.gen_range(0..20);
for _j in 0..numSet { for _j in 0..numSet {
// for (int j = 0; j < numSet; j++) { // 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); let numQueries = r.gen_range(0..20);
for _j in 0..numQueries { for _j in 0..numQueries {
// for (int j = 0; j < numQueries; j++) { // 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; let mut expected = query;
while expected < array.getSize() && !array.get(expected) { while expected < array.get_size() && !array.get(expected) {
expected += 1; expected += 1;
} }
let actual = array.getNextSet(query); let actual = array.getNextSet(query);

View File

@@ -57,7 +57,7 @@ impl BitArray {
Self { bits, size } Self { bits, size }
} }
pub fn getSize(&self) -> usize { pub fn get_size(&self) -> usize {
self.size self.size
} }

View File

@@ -156,12 +156,12 @@ fn test_get_row() {
// Should allocate // Should allocate
let array = matrix.getRow(2); let array = matrix.getRow(2);
assert_eq!(102, array.getSize()); assert_eq!(102, array.get_size());
// Should reallocate // Should reallocate
// let mut array2 = BitArray::with_size(60); // let mut array2 = BitArray::with_size(60);
let array2 = matrix.getRow(2); let array2 = matrix.getRow(2);
assert_eq!(102, array2.getSize()); assert_eq!(102, array2.get_size());
// Should use provided object, with original BitArray size // Should use provided object, with original BitArray size
// let mut array3 = BitArray::with_size(200); // let mut array3 = BitArray::with_size(200);

View File

@@ -20,7 +20,7 @@
// import com.google.zxing.LuminanceSource; // import com.google.zxing.LuminanceSource;
// import com.google.zxing.NotFoundException; // import com.google.zxing.NotFoundException;
use std::{borrow::Cow, rc::Rc}; use std::borrow::Cow;
use once_cell::unsync::OnceCell; use once_cell::unsync::OnceCell;
@@ -29,6 +29,10 @@ use crate::{Binarizer, Exceptions, LuminanceSource};
use super::{BitArray, BitMatrix}; 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 * 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 * 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 dswitkin@google.com (Daniel Switkin)
* @author Sean Owen * @author Sean Owen
*/ */
pub struct GlobalHistogramBinarizer { pub struct GlobalHistogramBinarizer<LS: LuminanceSource> {
//_luminances: Vec<u8>, //_luminances: Vec<u8>,
width: usize, width: usize,
height: usize, height: usize,
source: Box<dyn LuminanceSource>, source: LS,
black_matrix: OnceCell<BitMatrix>, black_matrix: OnceCell<BitMatrix>,
black_row_cache: Vec<OnceCell<BitArray>>, black_row_cache: Vec<OnceCell<BitArray>>,
} }
impl Binarizer for GlobalHistogramBinarizer { impl<LS: LuminanceSource> Binarizer for GlobalHistogramBinarizer<LS> {
fn getLuminanceSource(&self) -> &Box<dyn LuminanceSource> { type Source = LS;
fn get_luminance_source(&self) -> &Self::Source {
&self.source &self.source
} }
// Applies simple sharpening to the row data to improve performance of the 1D Readers. // 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 row = self.black_row_cache[y].get_or_try_init(|| {
let source = self.getLuminanceSource(); let source = self.get_luminance_source();
let width = source.getWidth(); let width = source.get_width();
let mut row = BitArray::with_size(width); let mut row = BitArray::with_size(width);
// self.initArrays(width); // self.initArrays(width);
let localLuminances = source.getRow(y); let localLuminances = source.get_row(y);
let mut localBuckets = [0; GlobalHistogramBinarizer::LUMINANCE_BUCKETS]; //self.buckets.clone(); let mut localBuckets = [0; LUMINANCE_BUCKETS]; //self.buckets.clone();
for x in 0..width { for x in 0..width {
// for (int x = 0; x < width; x++) { // for (int x = 0; x < width; x++) {
localBuckets[((localLuminances[x]) >> GlobalHistogramBinarizer::LUMINANCE_SHIFT) localBuckets[((localLuminances[x]) >> LUMINANCE_SHIFT) as usize] += 1;
as usize] += 1;
} }
let blackPoint = Self::estimateBlackPoint(&localBuckets)?; 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. // 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 let matrix = self
.black_matrix .black_matrix
.get_or_try_init(|| Self::build_black_matrix(&self.source))?; .get_or_try_init(|| Self::build_black_matrix(&self.source))?;
Ok(matrix) Ok(matrix)
} }
fn createBinarizer(&self, source: Box<dyn crate::LuminanceSource>) -> Rc<dyn Binarizer> { fn create_binarizer(&self, source: LS) -> Self {
Rc::new(GlobalHistogramBinarizer::new(source)) Self::new(source)
} }
fn getWidth(&self) -> usize { fn get_width(&self) -> usize {
self.width self.width
} }
fn getHeight(&self) -> usize { fn get_height(&self) -> usize {
self.height self.height
} }
} }
impl GlobalHistogramBinarizer { impl<LS: LuminanceSource> GlobalHistogramBinarizer<LS> {
const LUMINANCE_BITS: usize = 5;
const LUMINANCE_SHIFT: usize = 8 - GlobalHistogramBinarizer::LUMINANCE_BITS;
const LUMINANCE_BUCKETS: usize = 1 << GlobalHistogramBinarizer::LUMINANCE_BITS;
// const EMPTY: [u8; 0] = [0; 0]; // const EMPTY: [u8; 0] = [0; 0];
pub fn new(source: Box<dyn LuminanceSource>) -> Self { pub fn new(source: LS) -> Self {
Self { Self {
//_luminances: vec![0; source.getWidth()], //_luminances: vec![0; source.getWidth()],
width: source.getWidth(), width: source.get_width(),
height: source.getHeight(), height: source.get_height(),
black_matrix: OnceCell::new(), black_matrix: OnceCell::new(),
black_row_cache: vec![OnceCell::default(); source.getHeight()], black_row_cache: vec![OnceCell::default(); source.get_height()],
source, source,
} }
} }
fn build_black_matrix(source: &Box<dyn LuminanceSource>) -> Result<BitMatrix> { fn build_black_matrix(source: &LS) -> Result<BitMatrix> {
// let source = source.getLuminanceSource(); // let source = source.getLuminanceSource();
let width = source.getWidth(); let width = source.get_width();
let height = source.getHeight(); let height = source.get_height();
let mut matrix = BitMatrix::new(width as u32, height as u32)?; 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 // 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. // more robust on the blackbox tests than sampling a diagonal as we used to do.
// self.initArrays(width); // 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 y in 1..5 {
// for (int y = 1; y < 5; y++) { // for (int y = 1; y < 5; y++) {
let row = height * y / 5; let row = height * y / 5;
let localLuminances = source.getRow(row); let localLuminances = source.get_row(row);
let right = (width * 4) / 5; let right = (width * 4) / 5;
let mut x = width / 5; let mut x = width / 5;
while x < right { while x < right {
// for (int x = width / 5; x < right; x++) { // for (int x = width / 5; x < right; x++) {
let pixel = localLuminances[x]; let pixel = localLuminances[x];
localBuckets[(pixel >> GlobalHistogramBinarizer::LUMINANCE_SHIFT) as usize] += 1; localBuckets[(pixel >> LUMINANCE_SHIFT) as usize] += 1;
x += 1; x += 1;
} }
} }
@@ -167,7 +169,7 @@ impl GlobalHistogramBinarizer {
// We delay reading the entire image luminance until the black point estimation succeeds. // 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 // Although we end up reading four rows twice, it is consistent with our motto of
// "fail quickly" which is necessary for continuous scanning. // "fail quickly" which is necessary for continuous scanning.
let localLuminances = source.getMatrix(); let localLuminances = source.get_matrix();
for y in 0..height { for y in 0..height {
// for (int y = 0; y < height; y++) { // for (int y = 0; y < height; y++) {
let offset = y * width; let offset = y * width;
@@ -255,6 +257,6 @@ impl GlobalHistogramBinarizer {
x -= 1; x -= 1;
} }
Ok((bestValley as u32) << GlobalHistogramBinarizer::LUMINANCE_SHIFT) Ok((bestValley as u32) << LUMINANCE_SHIFT)
} }
} }

View File

@@ -20,7 +20,7 @@
// import com.google.zxing.LuminanceSource; // import com.google.zxing.LuminanceSource;
// import com.google.zxing.NotFoundException; // import com.google.zxing.NotFoundException;
use std::{borrow::Cow, rc::Rc}; use std::borrow::Cow;
use once_cell::unsync::OnceCell; use once_cell::unsync::OnceCell;
@@ -46,20 +46,22 @@ use super::{BitArray, BitMatrix, GlobalHistogramBinarizer};
* *
* @author dswitkin@google.com (Daniel Switkin) * @author dswitkin@google.com (Daniel Switkin)
*/ */
pub struct HybridBinarizer { pub struct HybridBinarizer<LS: LuminanceSource> {
//width: usize, //width: usize,
//height: usize, //height: usize,
//source: Box<dyn LuminanceSource>, //source: Box<dyn LuminanceSource>,
ghb: GlobalHistogramBinarizer, ghb: GlobalHistogramBinarizer<LS>,
black_matrix: OnceCell<BitMatrix>, black_matrix: OnceCell<BitMatrix>,
} }
impl Binarizer for HybridBinarizer { impl<LS: LuminanceSource> Binarizer for HybridBinarizer<LS> {
fn getLuminanceSource(&self) -> &Box<dyn LuminanceSource> { type Source = LS;
self.ghb.getLuminanceSource()
fn get_luminance_source(&self) -> &LS {
self.ghb.get_luminance_source()
} }
fn getBlackRow(&self, y: usize) -> Result<Cow<BitArray>> { fn get_black_row(&self, y: usize) -> Result<Cow<BitArray>> {
self.ghb.getBlackRow(y) 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 * 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. * 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 let matrix = self
.black_matrix .black_matrix
.get_or_try_init(|| Self::calculateBlackMatrix(&self.ghb))?; .get_or_try_init(|| Self::calculateBlackMatrix(&self.ghb))?;
Ok(matrix) Ok(matrix)
} }
fn createBinarizer(&self, source: Box<dyn LuminanceSource>) -> Rc<dyn Binarizer> { fn create_binarizer(&self, source: LS) -> Self {
Rc::new(HybridBinarizer::new(source)) Self::new(source)
} }
fn getWidth(&self) -> usize { fn get_width(&self) -> usize {
self.ghb.getWidth() self.ghb.get_width()
} }
fn getHeight(&self) -> usize { fn get_height(&self) -> usize {
self.ghb.getHeight() 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); let ghb = GlobalHistogramBinarizer::new(source);
Self { Self {
black_matrix: OnceCell::new(), 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 matrix;
let source = ghb.getLuminanceSource(); let source = ghb.get_luminance_source();
let width = source.getWidth(); let width = source.get_width();
let height = source.getHeight(); let height = source.get_height();
let matrix = if width >= HybridBinarizer::MINIMUM_DIMENSION let matrix = if width >= MINIMUM_DIMENSION && height >= MINIMUM_DIMENSION {
&& height >= HybridBinarizer::MINIMUM_DIMENSION let luminances = source.get_matrix();
{ let mut sub_width = width >> BLOCK_SIZE_POWER;
let luminances = source.getMatrix(); if (width & BLOCK_SIZE_MASK) != 0 {
let mut sub_width = width >> HybridBinarizer::BLOCK_SIZE_POWER;
if (width & HybridBinarizer::BLOCK_SIZE_MASK) != 0 {
sub_width += 1; sub_width += 1;
} }
let mut sub_height = height >> HybridBinarizer::BLOCK_SIZE_POWER; let mut sub_height = height >> BLOCK_SIZE_POWER;
if (height & HybridBinarizer::BLOCK_SIZE_MASK) != 0 { if (height & BLOCK_SIZE_MASK) != 0 {
sub_height += 1; sub_height += 1;
} }
let black_points = Self::calculateBlackPoints( let black_points = Self::calculateBlackPoints(
@@ -141,7 +144,7 @@ impl HybridBinarizer {
Ok(new_matrix) Ok(new_matrix)
} else { } else {
// If the image is too small, fall back to the global histogram approach. // 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()) Ok(m.clone())
}; };
// dbg!(matrix.to_string()); // dbg!(matrix.to_string());
@@ -162,18 +165,18 @@ impl HybridBinarizer {
black_points: &[Vec<u32>], black_points: &[Vec<u32>],
matrix: &mut BitMatrix, matrix: &mut BitMatrix,
) { ) {
let maxYOffset = height - HybridBinarizer::BLOCK_SIZE as u32; let maxYOffset = height - BLOCK_SIZE as u32;
let maxXOffset = width - HybridBinarizer::BLOCK_SIZE as u32; let maxXOffset = width - BLOCK_SIZE as u32;
for y in 0..sub_height { for y in 0..sub_height {
// for (int y = 0; y < subHeight; y++) { // 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 { if yoffset > maxYOffset {
yoffset = maxYOffset; yoffset = maxYOffset;
} }
let top = Self::cap(y, sub_height - 3); let top = Self::cap(y, sub_height - 3);
for x in 0..sub_width { for x in 0..sub_width {
// for (int x = 0; x < subWidth; x++) { // 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 { if xoffset > maxXOffset {
xoffset = maxXOffset; xoffset = maxXOffset;
} }
@@ -215,9 +218,9 @@ impl HybridBinarizer {
matrix: &mut BitMatrix, matrix: &mut BitMatrix,
) { ) {
let mut offset = yoffset * stride + xoffset; 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 (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++) { // 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. // 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 { if luminances[offset as usize + x] as u32 <= threshold {
@@ -240,18 +243,18 @@ impl HybridBinarizer {
width: u32, width: u32,
height: u32, height: u32,
) -> Vec<Vec<u32>> { ) -> Vec<Vec<u32>> {
let maxYOffset = height as usize - HybridBinarizer::BLOCK_SIZE; let maxYOffset = height as usize - BLOCK_SIZE;
let maxXOffset = width as usize - HybridBinarizer::BLOCK_SIZE; let maxXOffset = width as usize - BLOCK_SIZE;
let mut blackPoints = vec![vec![0; subWidth as usize]; subHeight as usize]; let mut blackPoints = vec![vec![0; subWidth as usize]; subHeight as usize];
for y in 0..subHeight { for y in 0..subHeight {
// for (int y = 0; y < subHeight; y++) { // 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 { if yoffset > maxYOffset as u32 {
yoffset = maxYOffset as u32; yoffset = maxYOffset as u32;
} }
for x in 0..subWidth { for x in 0..subWidth {
// for (int x = 0; x < subWidth; x++) { // 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 { if xoffset > maxXOffset as u32 {
xoffset = maxXOffset as u32; xoffset = maxXOffset as u32;
} }
@@ -261,9 +264,9 @@ impl HybridBinarizer {
let mut offset = yoffset * width + xoffset; let mut offset = yoffset * width + xoffset;
let mut yy = 0; 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 (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++) { // for (int xx = 0; xx < HybridBinarizer::BLOCK_SIZE; xx++) {
let pixel = luminances[offset as usize + xx]; let pixel = luminances[offset as usize + xx];
sum += pixel as u32; sum += pixel as u32;
@@ -276,13 +279,13 @@ impl HybridBinarizer {
} }
} }
// short-circuit min/max tests once dynamic range is met // 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 // finish the rest of the rows quickly
offset += width; offset += width;
yy += 1; yy += 1;
while yy < HybridBinarizer::BLOCK_SIZE { while yy < BLOCK_SIZE {
// for (yy++, offset += width; yy < HybridBinarizer::BLOCK_SIZE; yy++, offset += width) { // 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++) { // for (int xx = 0; xx < BLOCK_SIZE; xx++) {
sum += luminances[offset as usize + xx] as u32; 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. // The default estimate is the average of the values in the block.
let mut average = sum >> (HybridBinarizer::BLOCK_SIZE_POWER * 2); let mut average = sum >> (BLOCK_SIZE_POWER * 2);
if (max - min) as usize <= HybridBinarizer::MIN_DYNAMIC_RANGE { 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 // 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 // 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. // low contrast area into black and white pixels, essentially creating data out of noise.

View File

@@ -19,7 +19,7 @@ pub struct OtsuLevelBinarizer {
impl OtsuLevelBinarizer { impl OtsuLevelBinarizer {
fn generate_threshold_matrix(source: &dyn LuminanceSource) -> Result<BitMatrix> { fn generate_threshold_matrix(source: &dyn LuminanceSource) -> Result<BitMatrix> {
let image_buffer = { 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) return Err(Exceptions::ILLEGAL_ARGUMENT)
}; };
buff buff
@@ -36,9 +36,9 @@ impl OtsuLevelBinarizer {
pub fn new(source: Box<dyn LuminanceSource>) -> Self { pub fn new(source: Box<dyn LuminanceSource>) -> Self {
Self { Self {
width: source.getWidth(), width: source.get_width(),
height: source.getHeight(), height: source.get_height(),
black_row_cache: vec![OnceCell::default(); source.getHeight()], black_row_cache: vec![OnceCell::default(); source.get_height()],
source, source,
black_matrix: OnceCell::new(), black_matrix: OnceCell::new(),
} }
@@ -46,38 +46,38 @@ impl OtsuLevelBinarizer {
} }
impl Binarizer for OtsuLevelBinarizer { impl Binarizer for OtsuLevelBinarizer {
fn getLuminanceSource(&self) -> &Box<dyn crate::LuminanceSource> { fn get_luminance_source(&self) -> &Box<dyn crate::LuminanceSource> {
&self.source &self.source
} }
fn getBlackRow(&self, y: usize) -> Result<std::borrow::Cow<super::BitArray>> { fn get_black_row(&self, y: usize) -> Result<std::borrow::Cow<super::BitArray>> {
let row = self.black_row_cache[y].get_or_try_init(|| { 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(matrix.getRow(y as u32))
})?; })?;
Ok(Cow::Borrowed(row)) Ok(Cow::Borrowed(row))
} }
fn getBlackMatrix(&self) -> Result<&super::BitMatrix> { fn get_black_matrix(&self) -> Result<&super::BitMatrix> {
let matrix = self let matrix = self
.black_matrix .black_matrix
.get_or_try_init(|| Self::generate_threshold_matrix(self.source.as_ref()))?; .get_or_try_init(|| Self::generate_threshold_matrix(self.source.as_ref()))?;
Ok(matrix) Ok(matrix)
} }
fn createBinarizer( fn create_binarizer(
&self, &self,
source: Box<dyn crate::LuminanceSource>, source: Box<dyn crate::LuminanceSource>,
) -> std::rc::Rc<dyn Binarizer> { ) -> std::rc::Rc<dyn Binarizer> {
Rc::new(Self::new(source)) Rc::new(Self::new(source))
} }
fn getWidth(&self) -> usize { fn get_width(&self) -> usize {
self.width self.width
} }
fn getHeight(&self) -> usize { fn get_height(&self) -> usize {
self.height self.height
} }
} }

View File

@@ -18,7 +18,7 @@ use std::collections::HashMap;
use crate::{ use crate::{
common::{BitMatrix, DecoderRXingResult, DetectorRXingResult, Result}, common::{BitMatrix, DecoderRXingResult, DetectorRXingResult, Result},
BarcodeFormat, DecodeHintType, DecodeHintValue, Exceptions, RXingResult, BarcodeFormat, Binarizer, DecodeHintType, DecodeHintValue, Exceptions, RXingResult,
RXingResultMetadataType, RXingResultMetadataValue, Reader, RXingResultMetadataType, RXingResultMetadataValue, Reader,
}; };
@@ -52,7 +52,10 @@ impl Reader for DataMatrixReader {
* @throws FormatException if a Data Matrix code cannot be decoded * @throws FormatException if a Data Matrix code cannot be decoded
* @throws ChecksumException if error correction fails * @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()) 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 FormatException if a Data Matrix code cannot be decoded
* @throws ChecksumException if error correction fails * @throws ChecksumException if error correction fails
*/ */
fn decode_with_hints( fn decode_with_hints<B: Binarizer>(
&mut self, &mut self,
image: &mut crate::BinaryBitmap, image: &mut crate::BinaryBitmap<B>,
hints: &crate::DecodingHintDictionary, hints: &crate::DecodingHintDictionary,
) -> Result<crate::RXingResult> { ) -> Result<crate::RXingResult> {
let try_harder = matches!( let try_harder = matches!(
@@ -76,14 +79,14 @@ impl Reader for DataMatrixReader {
let decoderRXingResult; let decoderRXingResult;
let mut points = Vec::new(); let mut points = Vec::new();
if hints.contains_key(&DecodeHintType::PURE_BARCODE) { 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)?; decoderRXingResult = DECODER.decode(&bits)?;
points.clear(); points.clear();
} else { } else {
//Result<DatamatrixDetectorResult, Exceptions> //Result<DatamatrixDetectorResult, Exceptions>
decoderRXingResult = if let Ok(fnd) = || -> Result<DecoderRXingResult> { decoderRXingResult = if let Ok(fnd) = || -> Result<DecoderRXingResult> {
let detectorRXingResult = 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())?; let decoded = DECODER.decode(detectorRXingResult.getBits())?;
points = detectorRXingResult.getPoints().to_vec(); points = detectorRXingResult.getPoints().to_vec();
Ok(decoded) Ok(decoded)
@@ -91,14 +94,14 @@ impl Reader for DataMatrixReader {
fnd fnd
} else if try_harder { } else if try_harder {
if let Ok(fnd) = || -> Result<DecoderRXingResult> { 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())?; let decoded = DECODER.decode(detectorRXingResult.getBits())?;
points = detectorRXingResult.getPoints().to_vec(); points = detectorRXingResult.getPoints().to_vec();
Ok(decoded) Ok(decoded)
}() { }() {
fnd fnd
} else { } else {
let bits = self.extractPureBits(image.getBlackMatrix())?; let bits = self.extractPureBits(image.get_black_matrix())?;
DECODER.decode(&bits)? DECODER.decode(&bits)?
} }
} else { } else {

View File

@@ -2,7 +2,6 @@ use std::{
collections::{HashMap, HashSet}, collections::{HashMap, HashSet},
io::Write, io::Write,
path::PathBuf, path::PathBuf,
rc::Rc,
}; };
use crate::{ use crate::{
@@ -136,9 +135,7 @@ pub fn detect_in_file_with_hints(
.or_insert(DecodeHintValue::TryHarder(true)); .or_insert(DecodeHintValue::TryHarder(true));
multi_format_reader.decode_with_hints( multi_format_reader.decode_with_hints(
&mut BinaryBitmap::new(Rc::new(HybridBinarizer::new(Box::new( &mut BinaryBitmap::new(HybridBinarizer::new(BufferedImageLuminanceSource::new(img))),
BufferedImageLuminanceSource::new(img),
)))),
hints, hints,
) )
} }
@@ -163,9 +160,7 @@ pub fn detect_multiple_in_file_with_hints(
.or_insert(DecodeHintValue::TryHarder(true)); .or_insert(DecodeHintValue::TryHarder(true));
scanner.decode_multiple_with_hints( scanner.decode_multiple_with_hints(
&mut BinaryBitmap::new(Rc::new(HybridBinarizer::new(Box::new( &mut BinaryBitmap::new(HybridBinarizer::new(BufferedImageLuminanceSource::new(img))),
BufferedImageLuminanceSource::new(img),
)))),
hints, hints,
) )
} }
@@ -200,9 +195,9 @@ pub fn detect_in_luma_with_hints(
.or_insert(DecodeHintValue::TryHarder(true)); .or_insert(DecodeHintValue::TryHarder(true));
multi_format_reader.decode_with_hints( multi_format_reader.decode_with_hints(
&mut BinaryBitmap::new(Rc::new(HybridBinarizer::new(Box::new( &mut BinaryBitmap::new(HybridBinarizer::new(Luma8LuminanceSource::new(
Luma8LuminanceSource::new(luma, width, height), luma, width, height,
)))), ))),
hints, hints,
) )
} }
@@ -225,9 +220,9 @@ pub fn detect_multiple_in_luma_with_hints(
.or_insert(DecodeHintValue::TryHarder(true)); .or_insert(DecodeHintValue::TryHarder(true));
scanner.decode_multiple_with_hints( scanner.decode_multiple_with_hints(
&mut BinaryBitmap::new(Rc::new(HybridBinarizer::new(Box::new( &mut BinaryBitmap::new(HybridBinarizer::new(Luma8LuminanceSource::new(
Luma8LuminanceSource::new(luma, width, height), luma, width, height,
)))), ))),
hints, hints,
) )
} }

View File

@@ -15,7 +15,7 @@ pub struct Luma8LuminanceSource {
original_dimension: (u32, u32), original_dimension: (u32, u32),
} }
impl LuminanceSource for Luma8LuminanceSource { impl LuminanceSource for Luma8LuminanceSource {
fn getRow(&self, y: usize) -> Vec<u8> { fn get_row(&self, y: usize) -> Vec<u8> {
self.data self.data
.chunks_exact(self.original_dimension.0 as usize) .chunks_exact(self.original_dimension.0 as usize)
.skip(y + self.origin.1 as usize) .skip(y + self.origin.1 as usize)
@@ -27,7 +27,7 @@ impl LuminanceSource for Luma8LuminanceSource {
.collect() .collect()
} }
fn getMatrix(&self) -> Vec<u8> { fn get_matrix(&self) -> Vec<u8> {
self.data self.data
.iter() .iter()
.skip((self.original_dimension.0 * self.origin.1) as usize) .skip((self.original_dimension.0 * self.origin.1) as usize)
@@ -38,7 +38,7 @@ impl LuminanceSource for Luma8LuminanceSource {
.flat_map(|f| { .flat_map(|f| {
f.iter() f.iter()
.skip((self.origin.0) as usize) .skip((self.origin.0) as usize)
.take(self.getWidth()) .take(self.get_width())
.copied() .copied()
}) // flatten this all out }) // flatten this all out
.copied() // copy it over so that it's u8 .copied() // copy it over so that it's u8
@@ -46,11 +46,11 @@ impl LuminanceSource for Luma8LuminanceSource {
.collect() // collect into a vec .collect() // collect into a vec
} }
fn getWidth(&self) -> usize { fn get_width(&self) -> usize {
self.dimensions.0 as usize self.dimensions.0 as usize
} }
fn getHeight(&self) -> usize { fn get_height(&self) -> usize {
self.dimensions.1 as usize self.dimensions.1 as usize
} }
@@ -58,31 +58,25 @@ impl LuminanceSource for Luma8LuminanceSource {
self.inverted = !self.inverted; self.inverted = !self.inverted;
} }
fn isCropSupported(&self) -> bool { fn is_crop_supported(&self) -> bool {
true true
} }
fn crop( fn crop(&self, left: usize, top: usize, width: usize, height: usize) -> Result<Self> {
&self, Ok(Self {
left: usize,
top: usize,
width: usize,
height: usize,
) -> Result<Box<dyn LuminanceSource>> {
Ok(Box::new(Self {
dimensions: (width as u32, height as u32), dimensions: (width as u32, height as u32),
origin: (left as u32, top as u32), origin: (left as u32, top as u32),
data: self.data.clone(), data: self.data.clone(),
inverted: self.inverted, inverted: self.inverted,
original_dimension: self.original_dimension, original_dimension: self.original_dimension,
})) })
} }
fn isRotateSupported(&self) -> bool { fn is_rotate_supported(&self) -> bool {
true true
} }
fn rotateCounterClockwise(&self) -> Result<Box<dyn LuminanceSource>> { fn rotate_counter_clockwise(&self) -> Result<Self> {
let mut new_matrix = Self { let mut new_matrix = Self {
dimensions: self.dimensions, dimensions: self.dimensions,
origin: self.origin, origin: self.origin,
@@ -92,10 +86,10 @@ impl LuminanceSource for Luma8LuminanceSource {
}; };
new_matrix.transpose(); new_matrix.transpose();
new_matrix.reverseColumns(); 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( Err(crate::Exceptions::unsupported_operation_with(
"This luminance source does not support rotation by 45 degrees.", "This luminance source does not support rotation by 45 degrees.",
)) ))
@@ -104,12 +98,12 @@ impl LuminanceSource for Luma8LuminanceSource {
impl Luma8LuminanceSource { impl Luma8LuminanceSource {
fn reverseColumns(&mut self) { fn reverseColumns(&mut self) {
for i in 0..self.getWidth() { for i in 0..self.get_width() {
let mut j = 0; let mut j = 0;
let mut k = self.getWidth() - 1; let mut k = self.get_width() - 1;
while j < k { while j < k {
let offset_a = (self.getWidth() * i) + j; let offset_a = (self.get_width() * i) + j;
let offset_b = (self.getWidth() * i) + k; let offset_b = (self.get_width() * i) + k;
self.data.swap(offset_a, offset_b); self.data.swap(offset_a, offset_b);
j += 1; j += 1;
k -= 1; k -= 1;
@@ -118,10 +112,10 @@ impl Luma8LuminanceSource {
} }
fn transpose(&mut self) { fn transpose(&mut self) {
for i in 0..self.getHeight() { for i in 0..self.get_height() {
for j in i..self.getWidth() { for j in i..self.get_width() {
let offset_a = (self.getWidth() * i) + j; let offset_a = (self.get_width() * i) + j;
let offset_b = (self.getWidth() * j) + i; let offset_b = (self.get_width() * j) + i;
self.data.swap(offset_a, offset_b); self.data.swap(offset_a, offset_b);
} }
} }

View File

@@ -46,7 +46,7 @@ pub trait LuminanceSource {
* Always use the returned object, and ignore the .length of the array. * Always use the returned object, and ignore the .length of the array.
* @return An array containing the luminance data. * @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: * 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 * larger than width * height bytes on some platforms. Do not modify the contents
* of the result. * of the result.
*/ */
fn getMatrix(&self) -> Vec<u8>; fn get_matrix(&self) -> Vec<u8>;
/** /**
* @return The width of the bitmap. * @return The width of the bitmap.
*/ */
fn getWidth(&self) -> usize; fn get_width(&self) -> usize;
/** /**
* @return The height of the bitmap. * @return The height of the bitmap.
*/ */
fn getHeight(&self) -> usize; fn get_height(&self) -> usize;
/** /**
* @return Whether this subclass supports cropping. * @return Whether this subclass supports cropping.
*/ */
fn isCropSupported(&self) -> bool { fn is_crop_supported(&self) -> bool {
false false
} }
@@ -85,13 +85,10 @@ pub trait LuminanceSource {
* @param height The height of the rectangle to crop. * @param height The height of the rectangle to crop.
* @return A cropped version of this object. * @return A cropped version of this object.
*/ */
fn crop( fn crop(&self, _left: usize, _top: usize, _width: usize, _height: usize) -> Result<Self>
&self, where
_left: usize, Self: Sized,
_top: usize, {
_width: usize,
_height: usize,
) -> Result<Box<dyn LuminanceSource>> {
Err(Exceptions::unsupported_operation_with( Err(Exceptions::unsupported_operation_with(
"This luminance source does not support cropping.", "This luminance source does not support cropping.",
)) ))
@@ -100,7 +97,7 @@ pub trait LuminanceSource {
/** /**
* @return Whether this subclass supports counter-clockwise rotation. * @return Whether this subclass supports counter-clockwise rotation.
*/ */
fn isRotateSupported(&self) -> bool { fn is_rotate_supported(&self) -> bool {
false false
} }
@@ -118,7 +115,10 @@ pub trait LuminanceSource {
* *
* @return A rotated version of this object. * @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( Err(Exceptions::unsupported_operation_with(
"This luminance source does not support rotation by 90 degrees.", "This luminance source does not support rotation by 90 degrees.",
)) ))
@@ -130,7 +130,10 @@ pub trait LuminanceSource {
* *
* @return A rotated version of this object. * @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( Err(Exceptions::unsupported_operation_with(
"This luminance source does not support rotation by 45 degrees.", "This luminance source does not support rotation by 45 degrees.",
)) ))

View File

@@ -1144,7 +1144,7 @@ mod detector_test {
let img = image::open(filename).unwrap(); let img = image::open(filename).unwrap();
let lum_src = BufferedImageLuminanceSource::new(img); let lum_src = BufferedImageLuminanceSource::new(img);
let binarizer = HybridBinarizer::new(Box::new(lum_src)); let binarizer = HybridBinarizer::new(Box::new(lum_src));
let bitmatrix = binarizer.getBlackMatrix().unwrap(); let bitmatrix = binarizer.get_black_matrix().unwrap();
// let i: image::DynamicImage = bitmatrix.into(); // let i: image::DynamicImage = bitmatrix.into();
// i.save("dbgfle.png").expect("should write image"); // i.save("dbgfle.png").expect("should write image");

View File

@@ -18,7 +18,7 @@ use std::collections::HashMap;
use crate::{ use crate::{
common::{BitMatrix, DetectorRXingResult, Result}, common::{BitMatrix, DetectorRXingResult, Result},
BarcodeFormat, DecodeHintType, DecodeHintValue, Exceptions, RXingResult, BarcodeFormat, Binarizer, DecodeHintType, DecodeHintValue, Exceptions, RXingResult,
RXingResultMetadataType, Reader, RXingResultMetadataType, Reader,
}; };
@@ -41,7 +41,10 @@ impl Reader for MaxiCodeReader {
* @throws FormatException if a MaxiCode cannot be decoded * @throws FormatException if a MaxiCode cannot be decoded
* @throws ChecksumException if error correction fails * @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()) self.decode_with_hints(image, &HashMap::new())
} }
@@ -53,9 +56,9 @@ impl Reader for MaxiCodeReader {
* @throws FormatException if a MaxiCode cannot be decoded * @throws FormatException if a MaxiCode cannot be decoded
* @throws ChecksumException if error correction fails * @throws ChecksumException if error correction fails
*/ */
fn decode_with_hints( fn decode_with_hints<B: Binarizer>(
&mut self, &mut self,
image: &mut crate::BinaryBitmap, image: &mut crate::BinaryBitmap<B>,
hints: &crate::DecodingHintDictionary, hints: &crate::DecodingHintDictionary,
) -> Result<crate::RXingResult> { ) -> Result<crate::RXingResult> {
// Note that MaxiCode reader effectively always assumes PURE_BARCODE mode // Note that MaxiCode reader effectively always assumes PURE_BARCODE mode
@@ -68,12 +71,12 @@ impl Reader for MaxiCodeReader {
let mut rotation = None; let mut rotation = None;
let decoderRXingResult = if try_harder { 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()); rotation = Some(result.rotation());
let parsed_result = detector::read_bits(result.getBits())?; let parsed_result = detector::read_bits(result.getBits())?;
maxicode_decoder::decode_with_hints(&parsed_result, hints)? maxicode_decoder::decode_with_hints(&parsed_result, hints)?
} else { } else {
let bits = Self::extractPureBits(image.getBlackMatrix())?; let bits = Self::extractPureBits(image.get_black_matrix())?;
maxicode_decoder::decode_with_hints(&bits, hints)? maxicode_decoder::decode_with_hints(&bits, hints)?
}; };

View File

@@ -17,7 +17,7 @@
use std::collections::HashMap; use std::collections::HashMap;
use crate::common::Result; 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, * 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); pub struct ByQuadrantReader<T: Reader>(T);
impl<T: Reader> Reader for ByQuadrantReader<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()) self.decode_with_hints(image, &HashMap::new())
} }
fn decode_with_hints( fn decode_with_hints<B: Binarizer>(
&mut self, &mut self,
image: &mut crate::BinaryBitmap, image: &mut crate::BinaryBitmap<B>,
hints: &crate::DecodingHintDictionary, hints: &crate::DecodingHintDictionary,
) -> Result<crate::RXingResult> { ) -> Result<crate::RXingResult> {
let width = image.getWidth(); let width = image.get_width();
let height = image.getHeight(); let height = image.get_height();
let halfWidth = width / 2; let halfWidth = width / 2;
let halfHeight = height / 2; let halfHeight = height / 2;

View File

@@ -17,8 +17,8 @@
use std::collections::HashMap; use std::collections::HashMap;
use crate::{ use crate::{
common::Result, point, BinaryBitmap, DecodingHintDictionary, Exceptions, Point, RXingResult, common::Result, point, Binarizer, BinaryBitmap, DecodingHintDictionary, Exceptions, Point,
Reader, RXingResult, Reader,
}; };
use super::MultipleBarcodeReader; use super::MultipleBarcodeReader;
@@ -41,20 +41,20 @@ use super::MultipleBarcodeReader;
pub struct GenericMultipleBarcodeReader<T: Reader>(T); pub struct GenericMultipleBarcodeReader<T: Reader>(T);
impl<T: Reader> MultipleBarcodeReader for GenericMultipleBarcodeReader<T> { impl<T: Reader> MultipleBarcodeReader for GenericMultipleBarcodeReader<T> {
fn decode_multiple( fn decode_multiple<B: Binarizer>(
&mut self, &mut self,
image: &mut crate::BinaryBitmap, image: &mut BinaryBitmap<B>,
) -> Result<Vec<crate::RXingResult>> { ) -> Result<Vec<RXingResult>> {
self.decode_multiple_with_hints(image, &HashMap::new()) self.decode_multiple_with_hints(image, &HashMap::new())
} }
fn decode_multiple_with_hints( fn decode_multiple_with_hints<B: Binarizer>(
&mut self, &mut self,
image: &mut crate::BinaryBitmap, image: &mut BinaryBitmap<B>,
hints: &crate::DecodingHintDictionary, hints: &DecodingHintDictionary,
) -> Result<Vec<crate::RXingResult>> { ) -> Result<Vec<RXingResult>> {
let mut results = Vec::new(); 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() { if results.is_empty() {
return Err(Exceptions::NOT_FOUND); return Err(Exceptions::NOT_FOUND);
} }
@@ -69,9 +69,9 @@ impl<T: Reader> GenericMultipleBarcodeReader<T> {
Self(delegate) Self(delegate)
} }
fn doDecodeMultiple( fn do_decode_multiple<B: Binarizer>(
&mut self, &mut self,
image: &mut BinaryBitmap, image: &mut BinaryBitmap<B>,
hints: &DecodingHintDictionary, hints: &DecodingHintDictionary,
results: &mut Vec<RXingResult>, results: &mut Vec<RXingResult>,
xOffset: u32, xOffset: u32,
@@ -105,8 +105,8 @@ impl<T: Reader> GenericMultipleBarcodeReader<T> {
return; return;
} }
let width = image.getWidth(); let width = image.get_width();
let height = image.getHeight(); let height = image.get_height();
let mut minX: f32 = width as f32; let mut minX: f32 = width as f32;
let mut minY: f32 = height as f32; let mut minY: f32 = height as f32;
let mut maxX: f32 = 0.0; let mut maxX: f32 = 0.0;
@@ -133,7 +133,7 @@ impl<T: Reader> GenericMultipleBarcodeReader<T> {
// Decode left of barcode // Decode left of barcode
if minX > Self::MIN_DIMENSION_TO_RECUR { if minX > Self::MIN_DIMENSION_TO_RECUR {
self.doDecodeMultiple( self.do_decode_multiple(
&mut image.crop(0, 0, minX as usize, height), &mut image.crop(0, 0, minX as usize, height),
hints, hints,
results, results,
@@ -144,7 +144,7 @@ impl<T: Reader> GenericMultipleBarcodeReader<T> {
} }
// Decode above barcode // Decode above barcode
if minY > Self::MIN_DIMENSION_TO_RECUR { if minY > Self::MIN_DIMENSION_TO_RECUR {
self.doDecodeMultiple( self.do_decode_multiple(
&mut image.crop(0, 0, width, minY as usize), &mut image.crop(0, 0, width, minY as usize),
hints, hints,
results, results,
@@ -155,7 +155,7 @@ impl<T: Reader> GenericMultipleBarcodeReader<T> {
} }
// Decode right of barcode // Decode right of barcode
if maxX < (width as f32) - Self::MIN_DIMENSION_TO_RECUR { 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), &mut image.crop(maxX as usize, 0, width - maxX as usize, height),
hints, hints,
results, results,
@@ -166,7 +166,7 @@ impl<T: Reader> GenericMultipleBarcodeReader<T> {
} }
// Decode below barcode // Decode below barcode
if maxY < (height as f32) - Self::MIN_DIMENSION_TO_RECUR { 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), &mut image.crop(0, maxY as usize, width, height - maxY as usize),
hints, hints,
results, results,

View File

@@ -14,7 +14,7 @@
* limitations under the License. * 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. * 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 * @author Sean Owen
*/ */
pub trait MultipleBarcodeReader { pub trait MultipleBarcodeReader {
fn decode_multiple(&mut self, image: &mut BinaryBitmap) -> Result<Vec<RXingResult>>; fn decode_multiple<B: Binarizer>(
fn decode_multiple_with_hints(
&mut self, &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, hints: &DecodingHintDictionary,
) -> Result<Vec<RXingResult>>; ) -> Result<Vec<RXingResult>>;
} }

View File

@@ -23,7 +23,8 @@ use crate::{
decoder::{self, QRCodeDecoderMetaData}, decoder::{self, QRCodeDecoderMetaData},
QRCodeReader, QRCodeReader,
}, },
BarcodeFormat, Exceptions, RXingResult, RXingResultMetadataType, RXingResultMetadataValue, BarcodeFormat, Binarizer, Exceptions, RXingResult, RXingResultMetadataType,
RXingResultMetadataValue,
}; };
use super::detector::MultiDetector; use super::detector::MultiDetector;
@@ -37,20 +38,21 @@ use super::detector::MultiDetector;
#[derive(Default)] #[derive(Default)]
pub struct QRCodeMultiReader(QRCodeReader); pub struct QRCodeMultiReader(QRCodeReader);
impl MultipleBarcodeReader for QRCodeMultiReader { impl MultipleBarcodeReader for QRCodeMultiReader {
fn decode_multiple( fn decode_multiple<B: Binarizer>(
&mut self, &mut self,
image: &mut crate::BinaryBitmap, image: &mut crate::BinaryBitmap<B>,
) -> Result<Vec<crate::RXingResult>> { ) -> Result<Vec<RXingResult>> {
self.decode_multiple_with_hints(image, &HashMap::new()) self.decode_multiple_with_hints(image, &HashMap::new())
} }
fn decode_multiple_with_hints( fn decode_multiple_with_hints<B: Binarizer>(
&mut self, &mut self,
image: &mut crate::BinaryBitmap, image: &mut crate::BinaryBitmap<B>,
hints: &crate::DecodingHintDictionary, hints: &crate::DecodingHintDictionary,
) -> Result<Vec<crate::RXingResult>> { ) -> Result<Vec<RXingResult>> {
let mut results = Vec::new(); 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 { for detectorRXingResult in detectorRXingResults {
let mut proc = || -> Result<()> { let mut proc = || -> Result<()> {
let decoderRXingResult = decoder::qrcode_decoder::decode_bitmatrix_with_hints( let decoderRXingResult = decoder::qrcode_decoder::decode_bitmatrix_with_hints(

View File

@@ -14,14 +14,14 @@
* limitations under the License. * limitations under the License.
*/ */
use std::collections::HashMap; use std::collections::{HashMap, HashSet};
use crate::common::Result; use crate::common::Result;
use crate::{ use crate::{
aztec::AztecReader, datamatrix::DataMatrixReader, maxicode::MaxiCodeReader, aztec::AztecReader, datamatrix::DataMatrixReader, maxicode::MaxiCodeReader,
oned::MultiFormatOneDReader, pdf417::PDF417Reader, qrcode::QRCodeReader, BarcodeFormat, oned::MultiFormatOneDReader, pdf417::PDF417Reader, qrcode::QRCodeReader, BarcodeFormat,
BinaryBitmap, DecodeHintType, DecodeHintValue, DecodingHintDictionary, Exceptions, RXingResult, Binarizer, BinaryBitmap, DecodeHintType, DecodeHintValue, DecodingHintDictionary, Exceptions,
Reader, RXingResult, Reader,
}; };
/** /**
@@ -35,7 +35,8 @@ use crate::{
#[derive(Default)] #[derive(Default)]
pub struct MultiFormatReader { pub struct MultiFormatReader {
hints: DecodingHintDictionary, hints: DecodingHintDictionary,
readers: Vec<Box<dyn Reader>>, possible_formats: HashSet<BarcodeFormat>,
try_harder: bool,
} }
impl Reader for MultiFormatReader { impl Reader for MultiFormatReader {
@@ -48,8 +49,8 @@ impl Reader for MultiFormatReader {
* @return The contents of the image * @return The contents of the image
* @throws NotFoundException Any errors which occurred * @throws NotFoundException Any errors which occurred
*/ */
fn decode(&mut self, image: &mut crate::BinaryBitmap) -> Result<crate::RXingResult> { fn decode<B: Binarizer>(&mut self, image: &mut BinaryBitmap<B>) -> Result<RXingResult> {
self.set_ints(&HashMap::new()); self.set_hints(&HashMap::new());
self.decode_internal(image) self.decode_internal(image)
} }
@@ -61,20 +62,14 @@ impl Reader for MultiFormatReader {
* @return The contents of the image * @return The contents of the image
* @throws NotFoundException Any errors which occurred * @throws NotFoundException Any errors which occurred
*/ */
fn decode_with_hints( fn decode_with_hints<B: Binarizer>(
&mut self, &mut self,
image: &mut crate::BinaryBitmap, image: &mut BinaryBitmap<B>,
hints: &crate::DecodingHintDictionary, hints: &DecodingHintDictionary,
) -> Result<crate::RXingResult> { ) -> Result<RXingResult> {
self.set_ints(hints); self.set_hints(hints);
self.decode_internal(image) self.decode_internal(image)
} }
fn reset(&mut self) {
for reader in self.readers.iter_mut() {
reader.reset();
}
}
} }
impl MultiFormatReader { impl MultiFormatReader {
@@ -86,10 +81,13 @@ impl MultiFormatReader {
* @return The contents of the image * @return The contents of the image
* @throws NotFoundException Any errors which occurred * @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 // Make sure to set up the default state so we don't crash
if self.readers.is_empty() { if self.possible_formats.is_empty() {
self.set_ints(&HashMap::new()); self.set_hints(&HashMap::new());
} }
self.decode_internal(image) self.decode_internal(image)
} }
@@ -101,92 +99,130 @@ impl MultiFormatReader {
* *
* @param hints The set of hints to use for subsequent calls to decode(image) * @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(); self.hints = hints.clone();
let tryHarder = matches!( self.try_harder = matches!(
self.hints.get(&DecodeHintType::TRY_HARDER), self.hints.get(&DecodeHintType::TRY_HARDER),
Some(DecodeHintValue::TryHarder(true)) Some(DecodeHintValue::TryHarder(true))
); );
self.possible_formats = if let Some(DecodeHintValue::PossibleFormats(formats)) =
let formats = hints.get(&DecodeHintType::POSSIBLE_FORMATS); hints.get(&DecodeHintType::POSSIBLE_FORMATS)
let mut readers: Vec<Box<dyn Reader>> = Vec::new(); {
if let Some(DecodeHintValue::PossibleFormats(formats)) = formats { formats.clone()
let addOneDReader = formats.contains(&BarcodeFormat::UPC_A) } else {
|| formats.contains(&BarcodeFormat::UPC_E) HashSet::new()
|| 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;
} }
pub fn decode_internal(&mut self, image: &mut BinaryBitmap) -> Result<RXingResult> { pub fn decode_internal<B: Binarizer>(
if !self.readers.is_empty() { &mut self,
for reader in self.readers.iter_mut() { image: &mut BinaryBitmap<B>,
let res = reader.decode_with_hints(image, &self.hints); ) -> Result<RXingResult> {
if res.is_ok() { if !self.possible_formats.is_empty() {
return res; let res = self.decode_formats(image);
} if res.is_ok() {
return res;
} }
if matches!( if matches!(
self.hints.get(&DecodeHintType::ALSO_INVERTED), self.hints.get(&DecodeHintType::ALSO_INVERTED),
Some(DecodeHintValue::AlsoInverted(true)) Some(DecodeHintValue::AlsoInverted(true))
) { ) {
// Calling all readers again with inverted image // Calling all readers again with inverted image
image.getBlackMatrixMut().flip_self(); image.get_black_matrix_mut().flip_self();
for reader in self.readers.iter_mut() { let res = self.decode_formats(image);
let res = reader.decode_with_hints(image, &self.hints); if res.is_ok() {
if res.is_ok() { return res;
return res;
}
} }
} }
} }
Err(Exceptions::NOT_FOUND) Err(Exceptions::NOT_FOUND)
} }
fn decode_formats<B: Binarizer>(&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) =
MultiFormatOneDReader::new(&self.hints).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) =
MultiFormatOneDReader::new(&self.hints).decode_with_hints(image, &self.hints)
{
return Ok(res);
}
}
} else {
if !self.try_harder {
if let Ok(res) =
MultiFormatOneDReader::new(&self.hints).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) =
MultiFormatOneDReader::new(&self.hints).decode_with_hints(image, &self.hints)
{
return Ok(res);
}
}
}
Err(Exceptions::UNSUPPORTED_OPERATION)
}
} }

View File

@@ -49,7 +49,7 @@ impl Default for CodaBarReader {
} }
impl OneDReader for CodaBarReader { impl OneDReader for CodaBarReader {
fn decodeRow( fn decode_row(
&mut self, &mut self,
rowNumber: u32, rowNumber: u32,
row: &crate::common::BitArray, row: &crate::common::BitArray,
@@ -309,7 +309,7 @@ impl CodaBarReader {
self.counterLength = 0; self.counterLength = 0;
// Start from the first white bit. // Start from the first white bit.
let mut i = row.getNextUnset(0); let mut i = row.getNextUnset(0);
let end = row.getSize(); let end = row.get_size();
if i >= end { if i >= end {
return Err(Exceptions::NOT_FOUND); return Err(Exceptions::NOT_FOUND);
} }

View File

@@ -32,7 +32,7 @@ use super::{one_d_reader, OneDReader};
pub struct Code128Reader; pub struct Code128Reader;
impl OneDReader for Code128Reader { impl OneDReader for Code128Reader {
fn decodeRow( fn decode_row(
&mut self, &mut self,
rowNumber: u32, rowNumber: u32,
row: &crate::common::BitArray, row: &crate::common::BitArray,
@@ -294,7 +294,7 @@ impl OneDReader for Code128Reader {
nextStart = row.getNextUnset(nextStart); nextStart = row.getNextUnset(nextStart);
if !row.isRange( if !row.isRange(
nextStart, nextStart,
row.getSize().min(nextStart + (nextStart - lastStart) / 2), row.get_size().min(nextStart + (nextStart - lastStart) / 2),
false, false,
)? { )? {
return Err(Exceptions::NOT_FOUND); return Err(Exceptions::NOT_FOUND);
@@ -354,7 +354,7 @@ impl OneDReader for Code128Reader {
} }
impl Code128Reader { impl Code128Reader {
fn findStartPattern(&self, row: &BitArray) -> Result<[usize; 3]> { fn findStartPattern(&self, row: &BitArray) -> Result<[usize; 3]> {
let width = row.getSize(); let width = row.get_size();
let rowOffset = row.getNextSet(0); let rowOffset = row.getNextSet(0);
let mut counterPosition = 0; let mut counterPosition = 0;
@@ -371,7 +371,7 @@ impl Code128Reader {
let mut bestVariance = MAX_AVG_VARIANCE; let mut bestVariance = MAX_AVG_VARIANCE;
let mut bestMatch = -1_isize; let mut bestMatch = -1_isize;
for startCode in CODE_START_A..=CODE_START_C { for startCode in CODE_START_A..=CODE_START_C {
let variance = one_d_reader::patternMatchVariance( let variance = one_d_reader::pattern_match_variance(
&counters, &counters,
&CODE_PATTERNS[startCode as usize], &CODE_PATTERNS[startCode as usize],
MAX_INDIVIDUAL_VARIANCE, MAX_INDIVIDUAL_VARIANCE,
@@ -410,13 +410,13 @@ impl Code128Reader {
} }
fn decodeCode(&self, row: &BitArray, counters: &mut [u32; 6], rowOffset: usize) -> Result<u8> { 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 bestVariance = MAX_AVG_VARIANCE; // worst variance we'll accept
let mut bestMatch = -1_isize; let mut bestMatch = -1_isize;
for d in 0..CODE_PATTERNS.len() { for d in 0..CODE_PATTERNS.len() {
let pattern = &CODE_PATTERNS[d]; let pattern = &CODE_PATTERNS[d];
let variance = 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 { if variance < bestVariance {
bestVariance = variance; bestVariance = variance;
bestMatch = d as isize; bestMatch = d as isize;

View File

@@ -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)?; WRITER.encode_with_hints(toEncode, &BarcodeFormat::CODE_128, 0, 0, &hints)?;
if !expectedLoopback.is_empty() { if !expectedLoopback.is_empty() {
let row = encRXingResult.getRow(0); 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 actual = rtRXingResult.getText();
assert_eq!(expectedLoopback, actual); assert_eq!(expectedLoopback, actual);
} }
if compact { if compact {
//check that what is encoded compactly yields the same on loopback as what was encoded fast. //check that what is encoded compactly yields the same on loopback as what was encoded fast.
let row = encRXingResult.getRow(0); 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 actual = rtRXingResult.getText();
let encRXingResultFast = WRITER.encode(toEncode, &BarcodeFormat::CODE_128, 0, 0)?; let encRXingResultFast = WRITER.encode(toEncode, &BarcodeFormat::CODE_128, 0, 0)?;
let row = encRXingResultFast.getRow(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); assert_eq!(rtRXingResult.getText(), actual);
} }
Ok(encRXingResult) Ok(encRXingResult)

View File

@@ -40,7 +40,7 @@ impl Default for Code39Reader {
} }
} }
impl OneDReader for Code39Reader { impl OneDReader for Code39Reader {
fn decodeRow( fn decode_row(
&mut self, &mut self,
rowNumber: u32, rowNumber: u32,
row: &crate::common::BitArray, row: &crate::common::BitArray,
@@ -52,12 +52,12 @@ impl OneDReader for Code39Reader {
let start = Self::findAsteriskPattern(row, &mut counters)?; let start = Self::findAsteriskPattern(row, &mut counters)?;
// Read off white space // Read off white space
let mut nextStart = row.getNextSet(start[1] as usize); let mut nextStart = row.getNextSet(start[1] as usize);
let end = row.getSize(); let end = row.get_size();
let mut decodedChar; let mut decodedChar;
let mut lastStart; let mut lastStart;
loop { loop {
one_d_reader::recordPattern(row, nextStart, &mut counters)?; one_d_reader::record_pattern(row, nextStart, &mut counters)?;
let pattern = Self::toNarrowWidePattern(&counters); let pattern = Self::toNarrowWidePattern(&counters);
if pattern < 0 { if pattern < 0 {
return Err(Exceptions::NOT_FOUND); return Err(Exceptions::NOT_FOUND);
@@ -205,7 +205,7 @@ impl Code39Reader {
} }
fn findAsteriskPattern(row: &BitArray, counters: &mut [u32]) -> Result<Vec<u32>> { 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 rowOffset = row.getNextSet(0);
let mut counterPosition = 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"); BitMatrix::parse_strings(encodedRXingResult, "1", "0").expect("bitmatrix parse");
// let row = BitArray::with_size(matrix.getWidth() as usize); // let row = BitArray::with_size(matrix.getWidth() as usize);
let row = matrix.getRow(0); 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()); assert_eq!(expectedRXingResult, result.getText());
} }
} }

View File

@@ -45,7 +45,7 @@ impl Default for Code93Reader {
} }
impl OneDReader for Code93Reader { impl OneDReader for Code93Reader {
fn decodeRow( fn decode_row(
&mut self, &mut self,
rowNumber: u32, rowNumber: u32,
row: &crate::common::BitArray, row: &crate::common::BitArray,
@@ -54,7 +54,7 @@ impl OneDReader for Code93Reader {
let start = self.findAsteriskPattern(row)?; let start = self.findAsteriskPattern(row)?;
// Read off white space // Read off white space
let mut nextStart = row.getNextSet(start[1]); let mut nextStart = row.getNextSet(start[1]);
let end = row.getSize(); let end = row.get_size();
let mut theCounters = self.counters; let mut theCounters = self.counters;
theCounters.fill(0); theCounters.fill(0);
@@ -63,7 +63,7 @@ impl OneDReader for Code93Reader {
let mut decodedChar; let mut decodedChar;
let mut lastStart; let mut lastStart;
loop { loop {
one_d_reader::recordPattern(row, nextStart, &mut theCounters)?; one_d_reader::record_pattern(row, nextStart, &mut theCounters)?;
let pattern = Self::toPattern(&theCounters); let pattern = Self::toPattern(&theCounters);
if pattern < 0 { if pattern < 0 {
return Err(Exceptions::NOT_FOUND); return Err(Exceptions::NOT_FOUND);
@@ -163,7 +163,7 @@ impl Code93Reader {
} }
fn findAsteriskPattern(&mut self, row: &BitArray) -> Result<[usize; 2]> { fn findAsteriskPattern(&mut self, row: &BitArray) -> Result<[usize; 2]> {
let width = row.getSize(); let width = row.get_size();
let rowOffset = row.getNextSet(0); let rowOffset = row.getNextSet(0);
self.counters.fill(0); self.counters.fill(0);
@@ -385,7 +385,7 @@ mod Code93ReaderTestCase {
// let mut row = BitArray::with_size(matrix.getWidth() as usize); // let mut row = BitArray::with_size(matrix.getWidth() as usize);
let row = matrix.getRow(0); let row = matrix.getRow(0);
let result = sut let result = sut
.decodeRow(0, &row, &HashMap::new()) .decode_row(0, &row, &HashMap::new())
.expect("must decode"); .expect("must decode");
assert_eq!(expectedRXingResult, result.getText()); assert_eq!(expectedRXingResult, result.getText());
} }

View File

@@ -50,7 +50,7 @@ impl UPCEANReader for EAN13Reader {
// counters[1] = 0; // counters[1] = 0;
// counters[2] = 0; // counters[2] = 0;
// counters[3] = 0; // counters[3] = 0;
let end = row.getSize(); let end = row.get_size();
let mut rowOffset = startRange[1]; let mut rowOffset = startRange[1];
let mut lgPatternFound = 0; let mut lgPatternFound = 0;

View File

@@ -46,7 +46,7 @@ impl UPCEANReader for EAN8Reader {
// counters[1] = 0; // counters[1] = 0;
// counters[2] = 0; // counters[2] = 0;
// counters[3] = 0; // counters[3] = 0;
let end = row.getSize(); let end = row.get_size();
let mut rowOffset = startRange[1]; let mut rowOffset = startRange[1];
let mut x = 0; let mut x = 0;

View File

@@ -104,7 +104,7 @@ impl Default for ITFReader {
} }
impl OneDReader for ITFReader { impl OneDReader for ITFReader {
fn decodeRow( fn decode_row(
&mut self, &mut self,
rowNumber: u32, rowNumber: u32,
row: &crate::common::BitArray, row: &crate::common::BitArray,
@@ -189,7 +189,7 @@ impl ITFReader {
while payloadStart < payloadEnd { while payloadStart < payloadEnd {
// Get 10 runs of black/white. // 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 // Split them into each array
for k in 0..5 { for k in 0..5 {
let twoK = 2 * k; let twoK = 2 * k;
@@ -275,7 +275,7 @@ impl ITFReader {
* @throws NotFoundException Throws exception if no black lines are found in the row * @throws NotFoundException Throws exception if no black lines are found in the row
*/ */
fn skipWhiteSpace(row: &BitArray) -> Result<usize> { fn skipWhiteSpace(row: &BitArray) -> Result<usize> {
let width = row.getSize(); let width = row.get_size();
let endStart = row.getNextSet(0); let endStart = row.getNextSet(0);
if endStart == width { if endStart == width {
return Err(Exceptions::NOT_FOUND); return Err(Exceptions::NOT_FOUND);
@@ -312,8 +312,8 @@ impl ITFReader {
// Now recalculate the indices of where the 'endblock' starts & stops to // Now recalculate the indices of where the 'endblock' starts & stops to
// accommodate the reversed nature of the search // accommodate the reversed nature of the search
let temp = endPattern[0]; let temp = endPattern[0];
endPattern[0] = row.getSize() - endPattern[1]; endPattern[0] = row.get_size() - endPattern[1];
endPattern[1] = row.getSize() - temp; endPattern[1] = row.get_size() - temp;
Ok(endPattern) Ok(endPattern)
}; };
@@ -341,7 +341,7 @@ impl ITFReader {
) -> Result<[usize; 2]> { ) -> Result<[usize; 2]> {
let patternLength = pattern.len(); let patternLength = pattern.len();
let mut counters = vec![0u32; patternLength]; //new int[patternLength]; let mut counters = vec![0u32; patternLength]; //new int[patternLength];
let width = row.getSize(); let width = row.get_size();
let mut isWhite = false; let mut isWhite = false;
let mut counterPosition = 0; let mut counterPosition = 0;
@@ -352,7 +352,7 @@ impl ITFReader {
counters[counterPosition] += 1; counters[counterPosition] += 1;
} else { } else {
if counterPosition == patternLength - 1 { if counterPosition == patternLength - 1 {
if one_d_reader::patternMatchVariance( if one_d_reader::pattern_match_variance(
&counters, &counters,
pattern, pattern,
MAX_INDIVIDUAL_VARIANCE, MAX_INDIVIDUAL_VARIANCE,
@@ -390,7 +390,7 @@ impl ITFReader {
let max = PATTERNS.len(); let max = PATTERNS.len();
for (i, pattern) in PATTERNS.iter().enumerate().take(max) { for (i, pattern) in PATTERNS.iter().enumerate().take(max) {
let variance = 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 { if variance < bestVariance {
bestVariance = variance; bestVariance = variance;
bestMatch = i as isize; bestMatch = i as isize;

View File

@@ -24,25 +24,110 @@ use super::ITFReader;
use super::MultiFormatUPCEANReader; use super::MultiFormatUPCEANReader;
use super::OneDReader; use super::OneDReader;
use crate::common::Result; use crate::common::Result;
use crate::BarcodeFormat;
use crate::DecodeHintValue; use crate::DecodeHintValue;
use crate::Exceptions; use crate::Exceptions;
use crate::{BarcodeFormat, Binarizer, RXingResult};
/** /**
* @author dswitkin@google.com (Daniel Switkin) * @author dswitkin@google.com (Daniel Switkin)
* @author Sean Owen * @author Sean Owen
*/ */
#[derive(Default)] #[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,
}
impl OneDReader for MultiFormatOneDReader { impl OneDReader for MultiFormatOneDReader {
fn decodeRow( fn decode_row(
&mut self, &mut self,
rowNumber: u32, row_number: u32,
row: &crate::common::BitArray, row: &crate::common::BitArray,
hints: &crate::DecodingHintDictionary, hints: &DecodingHintDictionary,
) -> Result<crate::RXingResult> { ) -> Result<RXingResult> {
for reader in self.0.iter_mut() { // reader.decode_row(rowNumber, row, hints)
if let Ok(res) = reader.decodeRow(rowNumber, row, hints) { let Self {
possible_formats,
use_code_39_check_digit,
internal_hints,
} = 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) = RSS14Reader::default().decode_row(row_number, row, hints) {
return Ok(res);
}
}
if possible_formats.contains(&BarcodeFormat::RSS_EXPANDED) {
if let Ok(res) = RSSExpandedReader::default().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) = RSS14Reader::default().decode_row(row_number, row, hints) {
return Ok(res);
}
if let Ok(res) = RSSExpandedReader::default().decode_row(row_number, row, hints) {
return Ok(res); return Ok(res);
} }
} }
@@ -52,57 +137,23 @@ impl OneDReader for MultiFormatOneDReader {
} }
impl MultiFormatOneDReader { impl MultiFormatOneDReader {
pub fn new(hints: &DecodingHintDictionary) -> Self { pub fn new(hints: &DecodingHintDictionary) -> Self {
let useCode39CheckDigit = matches!( let use_code_39_check_digit = matches!(
hints.get(&DecodeHintType::ASSUME_CODE_39_CHECK_DIGIT), hints.get(&DecodeHintType::ASSUME_CODE_39_CHECK_DIGIT),
Some(DecodeHintValue::AssumeCode39CheckDigit(true)) Some(DecodeHintValue::AssumeCode39CheckDigit(true))
); );
let mut readers: Vec<Box<dyn OneDReader>> = Vec::new(); let possible_formats = if let Some(DecodeHintValue::PossibleFormats(p)) =
if let Some(DecodeHintValue::PossibleFormats(possibleFormats)) =
hints.get(&DecodeHintType::POSSIBLE_FORMATS) hints.get(&DecodeHintType::POSSIBLE_FORMATS)
{ {
if possibleFormats.contains(&BarcodeFormat::EAN_13) p.clone()
|| possibleFormats.contains(&BarcodeFormat::UPC_A) } else {
|| possibleFormats.contains(&BarcodeFormat::EAN_8) HashSet::new()
|| 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());
}
Self(readers) Self {
possible_formats,
use_code_39_check_digit,
internal_hints: hints.clone(),
}
} }
} }
@@ -111,20 +162,20 @@ use crate::DecodingHintDictionary;
use crate::RXingResultMetadataType; use crate::RXingResultMetadataType;
use crate::RXingResultMetadataValue; use crate::RXingResultMetadataValue;
use crate::Reader; use crate::Reader;
use std::collections::HashMap; use std::collections::{HashMap, HashSet};
impl Reader for MultiFormatOneDReader { 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()) self.decode_with_hints(image, &HashMap::new())
} }
// Note that we don't try rotation without the try harder flag, even if rotation was supported. // 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, &mut self,
image: &mut crate::BinaryBitmap, image: &mut crate::BinaryBitmap<B>,
hints: &DecodingHintDictionary, hints: &DecodingHintDictionary,
) -> Result<crate::RXingResult> { ) -> Result<RXingResult> {
let first_try = self.doDecode(image, hints); let first_try = self._do_decode(image, hints);
if first_try.is_ok() { if first_try.is_ok() {
return first_try; return first_try;
} }
@@ -133,9 +184,9 @@ impl Reader for MultiFormatOneDReader {
hints.get(&DecodeHintType::TRY_HARDER), hints.get(&DecodeHintType::TRY_HARDER),
Some(DecodeHintValue::TryHarder(true)) Some(DecodeHintValue::TryHarder(true))
); );
if tryHarder && image.isRotateSupported() { if tryHarder && image.is_rotate_supported() {
let mut rotatedImage = image.rotateCounterClockwise(); let mut rotatedImage = image.rotate_counter_clockwise();
let mut result = self.doDecode(&mut rotatedImage, hints)?; let mut result = self._do_decode(&mut rotatedImage, hints)?;
// Record that we found it rotated 90 degrees CCW / 270 degrees CW // Record that we found it rotated 90 degrees CCW / 270 degrees CW
let metadata = result.getRXingResultMetadata(); let metadata = result.getRXingResultMetadata();
let mut orientation = 270; let mut orientation = 270;
@@ -156,7 +207,7 @@ impl Reader for MultiFormatOneDReader {
RXingResultMetadataValue::Orientation(orientation), RXingResultMetadataValue::Orientation(orientation),
); );
// Update result points // Update result points
let height = rotatedImage.getHeight(); let height = rotatedImage.get_height();
let total_points = result.getPoints().len(); let total_points = result.getPoints().len();
let points = result.getPointsMut(); let points = result.getPointsMut();
for point in points.iter_mut().take(total_points) { for point in points.iter_mut().take(total_points) {
@@ -169,10 +220,4 @@ impl Reader for MultiFormatOneDReader {
Err(Exceptions::NOT_FOUND) Err(Exceptions::NOT_FOUND)
} }
} }
fn reset(&mut self) {
for reader in self.0.iter_mut() {
reader.reset();
}
}
} }

View File

@@ -15,11 +15,11 @@
*/ */
use crate::common::Result; use crate::common::Result;
use crate::BarcodeFormat;
use crate::DecodeHintValue; use crate::DecodeHintValue;
use crate::Exceptions; use crate::Exceptions;
use crate::RXingResult; use crate::RXingResult;
use crate::Reader; use crate::Reader;
use crate::{BarcodeFormat, Binarizer};
use super::EAN13Reader; use super::EAN13Reader;
use super::EAN8Reader; use super::EAN8Reader;
@@ -35,47 +35,122 @@ use super::{OneDReader, UPCEANReader};
* *
* @author Sean Owen * @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 { impl MultiFormatUPCEANReader {
pub fn new(hints: &DecodingHintDictionary) -> Self { pub fn new(hints: &DecodingHintDictionary) -> Self {
let mut readers: Vec<Box<dyn UPCEANReader>> = Vec::new(); let possible_formats = if let Some(DecodeHintValue::PossibleFormats(p)) =
if let Some(DecodeHintValue::PossibleFormats(possibleFormats)) =
hints.get(&DecodeHintType::POSSIBLE_FORMATS) hints.get(&DecodeHintType::POSSIBLE_FORMATS)
{ {
// Collection<BarcodeFormat> possibleFormats = hints == null ? null : p.clone()
// (Collection<BarcodeFormat>) hints.get(DecodeHintType.POSSIBLE_FORMATS); } else {
// Collection<UPCEANReader> readers = new ArrayList<>(); HashSet::default()
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());
}
Self(readers) Self { possible_formats }
} }
fn try_decode_function( fn try_decode_function<R: UPCEANReader>(
&self, &self,
reader: &Box<dyn UPCEANReader>, reader: &R,
rowNumber: u32, rowNumber: u32,
row: &crate::common::BitArray, row: &crate::common::BitArray,
hints: &crate::DecodingHintDictionary, hints: &DecodingHintDictionary,
startGuardPattern: &[usize; 2], startGuardPattern: &[usize; 2],
) -> Result<crate::RXingResult> { ) -> Result<RXingResult> {
let result = reader.decodeRowWithGuardRange(rowNumber, row, startGuardPattern, hints)?; let result = reader.decodeRowWithGuardRange(rowNumber, row, startGuardPattern, hints)?;
// Special case: a 12-digit code encoded in UPC-A is identical to a "0" // 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, // 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::DecodeHintType;
use crate::DecodingHintDictionary; use crate::DecodingHintDictionary;
use crate::RXingResultMetadataType; use crate::RXingResultMetadataType;
use crate::RXingResultMetadataValue; use crate::RXingResultMetadataValue;
use std::collections::HashMap; use std::collections::{HashMap, HashSet};
impl Reader for MultiFormatUPCEANReader { 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()) self.decode_with_hints(image, &HashMap::new())
} }
// Note that we don't try rotation without the try harder flag, even if rotation was supported. // 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, &mut self,
image: &mut crate::BinaryBitmap, image: &mut crate::BinaryBitmap<B>,
hints: &DecodingHintDictionary, hints: &DecodingHintDictionary,
) -> Result<crate::RXingResult> { ) -> Result<RXingResult> {
let first_try = self.doDecode(image, hints); let first_try = self._do_decode(image, hints);
if first_try.is_ok() { if first_try.is_ok() {
return first_try; return first_try;
} }
@@ -165,16 +218,16 @@ impl Reader for MultiFormatUPCEANReader {
hints.get(&DecodeHintType::TRY_HARDER), hints.get(&DecodeHintType::TRY_HARDER),
Some(DecodeHintValue::TryHarder(true)) Some(DecodeHintValue::TryHarder(true))
); );
if tryHarder && image.isRotateSupported() { if tryHarder && image.is_rotate_supported() {
let mut rotatedImage = image.rotateCounterClockwise(); let mut rotatedImage = image.rotate_counter_clockwise();
let mut result = self.doDecode(&mut rotatedImage, hints)?; let mut result = self._do_decode(&mut rotatedImage, hints)?;
// Record that we found it rotated 90 degrees CCW / 270 degrees CW // Record that we found it rotated 90 degrees CCW / 270 degrees CW
let metadata = result.getRXingResultMetadata(); let metadata = result.getRXingResultMetadata();
let mut orientation = 270; let mut orientation = 270;
if metadata.contains_key(&RXingResultMetadataType::ORIENTATION) { if metadata.contains_key(&RXingResultMetadataType::ORIENTATION) {
// But if we found it reversed in doDecode(), add in that result here: // But if we found it reversed in doDecode(), add in that result here:
orientation = (orientation orientation = (orientation
+ if let Some(crate::RXingResultMetadataValue::Orientation(or)) = + if let Some(RXingResultMetadataValue::Orientation(or)) =
metadata.get(&RXingResultMetadataType::ORIENTATION) metadata.get(&RXingResultMetadataType::ORIENTATION)
{ {
*or *or
@@ -188,7 +241,7 @@ impl Reader for MultiFormatUPCEANReader {
RXingResultMetadataValue::Orientation(orientation), RXingResultMetadataValue::Orientation(orientation),
); );
// Update result points // Update result points
let height = rotatedImage.getHeight(); let height = rotatedImage.get_height();
let total_points = result.getPoints().len(); let total_points = result.getPoints().len();
let points = result.getPointsMut(); let points = result.getPointsMut();
for point in points.iter_mut().take(total_points) { for point in points.iter_mut().take(total_points) {
@@ -201,10 +254,4 @@ impl Reader for MultiFormatUPCEANReader {
Err(Exceptions::NOT_FOUND) Err(Exceptions::NOT_FOUND)
} }
} }
fn reset(&mut self) {
for reader in self.0.iter_mut() {
reader.reset();
}
}
} }

View File

@@ -16,8 +16,8 @@
use crate::{ use crate::{
common::{BitArray, Result}, common::{BitArray, Result},
point, BinaryBitmap, DecodeHintType, DecodeHintValue, DecodingHintDictionary, Exceptions, point, Binarizer, BinaryBitmap, DecodeHintType, DecodeHintValue, DecodingHintDictionary,
RXingResult, RXingResultMetadataType, RXingResultMetadataValue, Reader, Exceptions, RXingResult, RXingResultMetadataType, RXingResultMetadataValue, Reader,
}; };
/** /**
@@ -42,45 +42,45 @@ pub trait OneDReader: Reader {
* @return The contents of the decoded barcode * @return The contents of the decoded barcode
* @throws NotFoundException Any spontaneous errors which occur * @throws NotFoundException Any spontaneous errors which occur
*/ */
fn doDecode( fn _do_decode<B: Binarizer>(
&mut self, &mut self,
image: &mut BinaryBitmap, image: &mut BinaryBitmap<B>,
hints: &DecodingHintDictionary, hints: &DecodingHintDictionary,
) -> Result<RXingResult> { ) -> Result<RXingResult> {
let mut hints = hints.clone(); let mut hints = hints.clone();
let width = image.getWidth(); let width = image.get_width();
let height = image.getHeight(); let height = image.get_height();
let tryHarder = matches!( let try_harder = matches!(
hints.get(&DecodeHintType::TRY_HARDER), hints.get(&DecodeHintType::TRY_HARDER),
Some(DecodeHintValue::TryHarder(true)) Some(DecodeHintValue::TryHarder(true))
); );
let rowStep = 1.max(height >> (if tryHarder { 8 } else { 5 })); let row_step = 1.max(height >> (if try_harder { 8 } else { 5 }));
let maxLines = if tryHarder { let max_lines = if try_harder {
height // Look at the whole image, not just the center height // Look at the whole image, not just the center
} else { } else {
15 // 15 rows spaced 1/32 apart is roughly the middle half of the image 15 // 15 rows spaced 1/32 apart is roughly the middle half of the image
}; };
let middle = height / 2; 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: // Scanning from the middle out. Determine which row we're looking at next:
let rowStepsAboveOrBelow = (x + 1) / 2; let row_steps_above_or_below = (x + 1) / 2;
let isAbove = (x & 0x01) == 0; // i.e. is x even? let is_above = (x & 0x01) == 0; // i.e. is x even?
let rowNumber: isize = middle as isize let row_number: isize = middle as isize
+ rowStep as isize + row_step as isize
* (if isAbove { * (if is_above {
rowStepsAboveOrBelow as isize row_steps_above_or_below as isize
} else { } 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 // Oops, if we run off the top or bottom, stop
break; break;
} }
// Estimate black point for this row and load it: // 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 res
} else { } else {
continue; continue;
@@ -104,7 +104,7 @@ pub trait OneDReader: Reader {
hints.remove(&DecodeHintType::NEED_RESULT_POINT_CALLBACK); hints.remove(&DecodeHintType::NEED_RESULT_POINT_CALLBACK);
} }
} }
let Ok(mut result) = self.decodeRow(rowNumber as u32, &row, &hints) else { let Ok(mut result) = self.decode_row(row_number as u32, &row, &hints) else {
continue continue
}; };
// We found our barcode // We found our barcode
@@ -140,7 +140,7 @@ pub trait OneDReader: Reader {
* @throws ChecksumException if a potential barcode is found but does not pass its checksum * @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 * @throws FormatException if a potential barcode is found but format is invalid
*/ */
fn decodeRow( fn decode_row(
&mut self, &mut self,
rowNumber: u32, rowNumber: u32,
row: &BitArray, row: &BitArray,
@@ -158,39 +158,42 @@ pub trait OneDReader: Reader {
* @param maxIndividualVariance The most any counter can differ before we give up * @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 * @return ratio of total variance between counters and pattern compared to total pattern size
*/ */
pub fn patternMatchVariance(counters: &[u32], pattern: &[u32], maxIndividualVariance: f32) -> f32 { pub fn pattern_match_variance(
let mut maxIndividualVariance = maxIndividualVariance; counters: &[u32],
let numCounters = counters.len(); pattern: &[u32],
mut max_individual_variance: f32,
) -> f32 {
let num_counters = counters.len();
let mut total = 0.0; let mut total = 0.0;
let mut patternLength = 0; let mut pattern_length = 0;
for i in 0..numCounters { for i in 0..num_counters {
total += counters[i] as f32; 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 // If we don't even have one pixel per unit of bar width, assume this is too small
// to reliably match, so fail: // to reliably match, so fail:
return f32::INFINITY; return f32::INFINITY;
} }
let unitBarWidth = total / patternLength as f32; let unit_bar_width = total / pattern_length as f32;
maxIndividualVariance *= unitBarWidth; max_individual_variance *= unit_bar_width;
let mut totalVariance = 0.0; let mut total_variance = 0.0;
for x in 0..numCounters { for x in 0..num_counters {
let counter = counters[x]; let counter = counters[x];
let scaledPattern = (pattern[x] as f32) * unitBarWidth; let scaled_pattern = (pattern[x] as f32) * unit_bar_width;
let variance = if (counter as f32) > scaledPattern { let variance = if (counter as f32) > scaled_pattern {
counter as f32 - scaledPattern counter as f32 - scaled_pattern
} else { } else {
scaledPattern - counter as f32 scaled_pattern - counter as f32
}; };
if variance > maxIndividualVariance { if variance > max_individual_variance {
return f32::INFINITY; 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 * @throws NotFoundException if counters cannot be filled entirely from row before running out
* of pixels * of pixels
*/ */
pub fn recordPattern(row: &BitArray, start: usize, counters: &mut [u32]) -> Result<()> { pub fn record_pattern(row: &BitArray, start: usize, counters: &mut [u32]) -> Result<()> {
let numCounters = counters.len(); let num_counters = counters.len();
counters.fill(0); counters.fill(0);
let end = row.getSize(); let end = row.get_size();
if start >= end { if start >= end {
return Err(Exceptions::NOT_FOUND); return Err(Exceptions::NOT_FOUND);
} }
let mut isWhite = !row.get(start); let mut is_white = !row.get(start);
let mut counterPosition = 0; let mut counter_position = 0;
let mut i = start; let mut i = start;
while i < end { while i < end {
if row.get(i) != isWhite { if row.get(i) != is_white {
counters[counterPosition] += 1; counters[counter_position] += 1;
} else { } else {
counterPosition += 1; counter_position += 1;
if counterPosition == numCounters { if counter_position == num_counters {
break; break;
} else { } else {
counters[counterPosition] = 1; counters[counter_position] = 1;
isWhite = !isWhite; is_white = !is_white;
} }
} }
i += 1; i += 1;
} }
// If we read fully the last section of pixels and filled up our counters -- or filled // 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. // 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); return Err(Exceptions::NOT_FOUND);
} }
Ok(()) 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; let mut start = start;
// This could be more efficient I guess // 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); let mut last = row.get(start);
while start > 0 && numTransitionsLeft >= 0 { while start > 0 && num_transitions_left >= 0 {
start -= 1; start -= 1;
if row.get(start) != last { if row.get(start) != last {
numTransitionsLeft -= 1; num_transitions_left -= 1;
last = !last; last = !last;
} }
} }
if numTransitionsLeft >= 0 { if num_transitions_left >= 0 {
return Err(Exceptions::NOT_FOUND); return Err(Exceptions::NOT_FOUND);
} }
recordPattern(row, start + 1, counters)?; record_pattern(row, start + 1, counters)?;
Ok(()) Ok(())
} }

View File

@@ -33,8 +33,11 @@ pub trait AbstractRSSReaderTrait: OneDReader {
fn parseFinderValue(counters: &[u32], finderPatterns: &[[u32; 4]]) -> Result<u32> { fn parseFinderValue(counters: &[u32], finderPatterns: &[[u32; 4]]) -> Result<u32> {
for (value, pattern) in finderPatterns.iter().enumerate() { for (value, pattern) in finderPatterns.iter().enumerate() {
if one_d_reader::patternMatchVariance(counters, pattern, Self::MAX_INDIVIDUAL_VARIANCE) if one_d_reader::pattern_match_variance(
< Self::MAX_AVG_VARIANCE counters,
pattern,
Self::MAX_INDIVIDUAL_VARIANCE,
) < Self::MAX_AVG_VARIANCE
{ {
return Ok(value as u32); return Ok(value as u32);
} }

View File

@@ -38,7 +38,7 @@ pub struct AI01392xDecoder<'a> {
impl AI01decoder for AI01392xDecoder<'_> {} impl AI01decoder for AI01392xDecoder<'_> {}
impl AbstractExpandedDecoder for AI01392xDecoder<'_> { impl AbstractExpandedDecoder for AI01392xDecoder<'_> {
fn parseInformation(&mut self) -> Result<String> { 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); return Err(crate::Exceptions::NOT_FOUND);
} }

View File

@@ -38,7 +38,7 @@ pub struct AI01393xDecoder<'a> {
impl AI01decoder for AI01393xDecoder<'_> {} impl AI01decoder for AI01393xDecoder<'_> {}
impl AbstractExpandedDecoder for AI01393xDecoder<'_> { impl AbstractExpandedDecoder for AI01393xDecoder<'_> {
fn parseInformation(&mut self) -> Result<String> { 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); return Err(crate::Exceptions::NOT_FOUND);
} }

View File

@@ -54,7 +54,7 @@ impl AI01weightDecoder for AI013x0x1xDecoder<'_> {
impl AI01decoder for AI013x0x1xDecoder<'_> {} impl AI01decoder for AI013x0x1xDecoder<'_> {}
impl AbstractExpandedDecoder for AI013x0x1xDecoder<'_> { impl AbstractExpandedDecoder for AI013x0x1xDecoder<'_> {
fn parseInformation(&mut self) -> Result<String> { 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 != Self::HEADER_SIZE + Self::GTIN_SIZE as usize + Self::WEIGHT_SIZE + Self::DATE_SIZE
{ {
return Err(crate::Exceptions::NOT_FOUND); return Err(crate::Exceptions::NOT_FOUND);

View File

@@ -50,7 +50,7 @@ impl AI01weightDecoder for AI013x0xDecoder<'_> {
} }
impl AbstractExpandedDecoder for AI013x0xDecoder<'_> { impl AbstractExpandedDecoder for AI013x0xDecoder<'_> {
fn parseInformation(&mut self) -> Result<String> { 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::HEADER_SIZE + Self::GTIN_SIZE as usize + Self::WEIGHT_SIZE
{ {
return Err(crate::Exceptions::NOT_FOUND); return Err(crate::Exceptions::NOT_FOUND);

View File

@@ -82,8 +82,8 @@ impl<'a> GeneralAppIdDecoder<'_> {
fn isStillNumeric(&self, pos: usize) -> bool { fn isStillNumeric(&self, pos: usize) -> bool {
// It's numeric if it still has 7 positions // It's numeric if it still has 7 positions
// and one of the first 4 bits is "1". // and one of the first 4 bits is "1".
if pos + 7 > self.information.getSize() { if pos + 7 > self.information.get_size() {
return pos + 4 <= self.information.getSize(); return pos + 4 <= self.information.get_size();
} }
for i in pos..pos + 3 { for i in pos..pos + 3 {
@@ -97,17 +97,17 @@ impl<'a> GeneralAppIdDecoder<'_> {
} }
fn decodeNumeric(&self, pos: usize) -> Result<DecodedNumeric> { 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); let numeric = self.extractNumericValueFromBitArray(pos, 4);
if numeric == 0 { if numeric == 0 {
return DecodedNumeric::new( return DecodedNumeric::new(
self.information.getSize(), self.information.get_size(),
DecodedNumeric::FNC1, DecodedNumeric::FNC1,
DecodedNumeric::FNC1, DecodedNumeric::FNC1,
); );
} }
return DecodedNumeric::new( return DecodedNumeric::new(
self.information.getSize(), self.information.get_size(),
numeric - 1, numeric - 1,
DecodedNumeric::FNC1, DecodedNumeric::FNC1,
); );
@@ -263,10 +263,10 @@ impl<'a> GeneralAppIdDecoder<'_> {
self.current.incrementPosition(3); self.current.incrementPosition(3);
self.current.setNumeric(); self.current.setNumeric();
} else if self.isAlphaTo646ToAlphaLatch(self.current.getPosition()) { } 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); self.current.incrementPosition(5);
} else { } else {
self.current.setPosition(self.information.getSize()); self.current.setPosition(self.information.get_size());
} }
self.current.setAlpha(); self.current.setAlpha();
@@ -295,10 +295,10 @@ impl<'a> GeneralAppIdDecoder<'_> {
self.current.incrementPosition(3); self.current.incrementPosition(3);
self.current.setNumeric(); self.current.setNumeric();
} else if self.isAlphaTo646ToAlphaLatch(self.current.getPosition()) { } 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); self.current.incrementPosition(5);
} else { } else {
self.current.setPosition(self.information.getSize()); self.current.setPosition(self.information.get_size());
} }
self.current.setIsoIec646(); self.current.setIsoIec646();
@@ -308,7 +308,7 @@ impl<'a> GeneralAppIdDecoder<'_> {
} }
fn isStillIsoIec646(&self, pos: usize) -> bool { fn isStillIsoIec646(&self, pos: usize) -> bool {
if pos + 5 > self.information.getSize() { if pos + 5 > self.information.get_size() {
return false; return false;
} }
@@ -317,7 +317,7 @@ impl<'a> GeneralAppIdDecoder<'_> {
return true; return true;
} }
if pos + 7 > self.information.getSize() { if pos + 7 > self.information.get_size() {
return false; return false;
} }
@@ -326,7 +326,7 @@ impl<'a> GeneralAppIdDecoder<'_> {
return true; return true;
} }
if pos + 8 > self.information.getSize() { if pos + 8 > self.information.get_size() {
return false; return false;
} }
@@ -394,7 +394,7 @@ impl<'a> GeneralAppIdDecoder<'_> {
} }
fn isStillAlpha(&self, pos: usize) -> bool { fn isStillAlpha(&self, pos: usize) -> bool {
if pos + 5 > self.information.getSize() { if pos + 5 > self.information.get_size() {
return false; return false;
} }
@@ -404,7 +404,7 @@ impl<'a> GeneralAppIdDecoder<'_> {
return true; return true;
} }
if pos + 6 > self.information.getSize() { if pos + 6 > self.information.get_size() {
return false; return false;
} }
@@ -452,12 +452,12 @@ impl<'a> GeneralAppIdDecoder<'_> {
} }
fn isAlphaTo646ToAlphaLatch(&self, pos: usize) -> bool { fn isAlphaTo646ToAlphaLatch(&self, pos: usize) -> bool {
if pos + 1 > self.information.getSize() { if pos + 1 > self.information.get_size() {
return false; return false;
} }
let mut i = 0; 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 i == 2 {
if !self.information.get(pos + 2) { if !self.information.get(pos + 2) {
return false; return false;
@@ -474,7 +474,7 @@ impl<'a> GeneralAppIdDecoder<'_> {
fn isAlphaOr646ToNumericLatch(&self, pos: usize) -> bool { fn isAlphaOr646ToNumericLatch(&self, pos: usize) -> bool {
// Next is alphanumeric if there are 3 positions and they are all zeros // 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; return false;
} }
@@ -490,12 +490,12 @@ impl<'a> GeneralAppIdDecoder<'_> {
fn isNumericToAlphaNumericLatch(&self, pos: usize) -> bool { fn isNumericToAlphaNumericLatch(&self, pos: usize) -> bool {
// Next is alphanumeric if there are 4 positions and they are all zeros, or // 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 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; return false;
} }
let mut i = 0; 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) { if self.information.get(pos + i) {
return false; return false;
} }

View File

@@ -177,8 +177,8 @@ fn assertCorrectImage2binary(fileName: &str, expected: &str) {
let binaryMap = BinaryBitmap::new(Rc::new(GlobalHistogramBinarizer::new(Box::new( let binaryMap = BinaryBitmap::new(Rc::new(GlobalHistogramBinarizer::new(Box::new(
BufferedImageLuminanceSource::new(image), BufferedImageLuminanceSource::new(image),
)))); ))));
let rowNumber = binaryMap.getHeight() / 2; let rowNumber = binaryMap.get_height() / 2;
let row = binaryMap.getBlackRow(rowNumber).expect("row"); let row = binaryMap.get_black_row(rowNumber).expect("row");
// let pairs = Vec::new(); // let pairs = Vec::new();
// try { // try {

View File

@@ -74,12 +74,12 @@ fn assertCorrectImage2result(fileName: &str, expected: ExpandedProductParsedRXin
let binaryMap = BinaryBitmap::new(Rc::new(GlobalHistogramBinarizer::new(Box::new( let binaryMap = BinaryBitmap::new(Rc::new(GlobalHistogramBinarizer::new(Box::new(
BufferedImageLuminanceSource::new(image), BufferedImageLuminanceSource::new(image),
)))); ))));
let rowNumber = binaryMap.getHeight() / 2; let rowNumber = binaryMap.get_height() / 2;
let row = binaryMap.getBlackRow(rowNumber).expect("get row"); let row = binaryMap.get_black_row(rowNumber).expect("get row");
let mut rssExpandedReader = RSSExpandedReader::new(); let mut rssExpandedReader = RSSExpandedReader::new();
let theRXingResult = rssExpandedReader let theRXingResult = rssExpandedReader
.decodeRow(rowNumber as u32, &row, &HashMap::new()) .decode_row(rowNumber as u32, &row, &HashMap::new())
.expect("must decode"); .expect("must decode");
assert_eq!( assert_eq!(

View File

@@ -187,12 +187,12 @@ fn assertCorrectImage2string(fileName: &str, expected: &str) {
let binaryMap = BinaryBitmap::new(Rc::new(GlobalHistogramBinarizer::new(Box::new( let binaryMap = BinaryBitmap::new(Rc::new(GlobalHistogramBinarizer::new(Box::new(
BufferedImageLuminanceSource::new(image), BufferedImageLuminanceSource::new(image),
)))); ))));
let rowNumber = binaryMap.getHeight() / 2; let rowNumber = binaryMap.get_height() / 2;
let row = binaryMap.getBlackRow(rowNumber).expect("get row"); let row = binaryMap.get_black_row(rowNumber).expect("get row");
let mut rssExpandedReader = RSSExpandedReader::new(); let mut rssExpandedReader = RSSExpandedReader::new();
let result = rssExpandedReader let result = rssExpandedReader
.decodeRow(rowNumber as u32, &row, &HashMap::new()) .decode_row(rowNumber as u32, &row, &HashMap::new())
.expect("should decode"); .expect("should decode");
assert_eq!(&BarcodeFormat::RSS_EXPANDED, result.getBarcodeFormat()); assert_eq!(&BarcodeFormat::RSS_EXPANDED, result.getBarcodeFormat());

View File

@@ -45,8 +45,8 @@ fn testFindFinderPatterns() {
let binaryMap = BinaryBitmap::new(Rc::new(GlobalHistogramBinarizer::new(Box::new( let binaryMap = BinaryBitmap::new(Rc::new(GlobalHistogramBinarizer::new(Box::new(
BufferedImageLuminanceSource::new(image), BufferedImageLuminanceSource::new(image),
)))); ))));
let rowNumber = binaryMap.getHeight() as u32 / 2; let rowNumber = binaryMap.get_height() as u32 / 2;
let row = binaryMap.getBlackRow(rowNumber as usize).expect("ok"); let row = binaryMap.get_black_row(rowNumber as usize).expect("ok");
let mut previousPairs = Vec::new(); //new ArrayList<>(); let mut previousPairs = Vec::new(); //new ArrayList<>();
let mut rssExpandedReader = RSSExpandedReader::new(); let mut rssExpandedReader = RSSExpandedReader::new();
@@ -91,8 +91,8 @@ fn testRetrieveNextPairPatterns() {
let binaryMap = BinaryBitmap::new(Rc::new(GlobalHistogramBinarizer::new(Box::new( let binaryMap = BinaryBitmap::new(Rc::new(GlobalHistogramBinarizer::new(Box::new(
BufferedImageLuminanceSource::new(image), BufferedImageLuminanceSource::new(image),
)))); ))));
let rowNumber = binaryMap.getHeight() as u32 / 2; let rowNumber = binaryMap.get_height() as u32 / 2;
let row = binaryMap.getBlackRow(rowNumber as usize).expect("create"); let row = binaryMap.get_black_row(rowNumber as usize).expect("create");
let mut previousPairs = Vec::new(); //new ArrayList<>(); let mut previousPairs = Vec::new(); //new ArrayList<>();
let mut rssExpandedReader = RSSExpandedReader::new(); let mut rssExpandedReader = RSSExpandedReader::new();
@@ -120,7 +120,7 @@ fn testDecodeCheckCharacter() {
BufferedImageLuminanceSource::new(image.clone()), BufferedImageLuminanceSource::new(image.clone()),
)))); ))));
let row = binaryMap let row = binaryMap
.getBlackRow(binaryMap.getHeight() / 2) .get_black_row(binaryMap.get_height() / 2)
.expect("create"); .expect("create");
let startEnd = [145, 243]; //image pixels where the A1 pattern starts (at 124) and ends (at 214) let startEnd = [145, 243]; //image pixels where the A1 pattern starts (at 124) and ends (at 214)
@@ -148,7 +148,7 @@ fn testDecodeDataCharacter() {
BufferedImageLuminanceSource::new(image.clone()), BufferedImageLuminanceSource::new(image.clone()),
)))); ))));
let row = binaryMap let row = binaryMap
.getBlackRow(binaryMap.getHeight() / 2) .get_black_row(binaryMap.get_height() / 2)
.expect("create"); .expect("create");
let startEnd = [145, 243]; //image pixels where the A1 pattern starts (at 124) and ends (at 214) let startEnd = [145, 243]; //image pixels where the A1 pattern starts (at 124) and ends (at 214)

View File

@@ -29,14 +29,14 @@ use std::collections::HashMap;
use crate::{ use crate::{
common::{BitArray, Result}, common::{BitArray, Result},
oned::{ oned::{
recordPattern, recordPatternInReverse, record_pattern, record_pattern_in_reverse,
rss::{ rss::{
rss_utils, AbstractRSSReaderTrait, DataCharacter, DataCharacterTrait, FinderPattern, rss_utils, AbstractRSSReaderTrait, DataCharacter, DataCharacterTrait, FinderPattern,
Pair, Pair,
}, },
OneDReader, OneDReader,
}, },
BarcodeFormat, DecodeHintType, DecodeHintValue, DecodingHintDictionary, Exceptions, BarcodeFormat, Binarizer, DecodeHintType, DecodeHintValue, DecodingHintDictionary, Exceptions,
RXingResult, RXingResultMetadataType, RXingResultMetadataValue, Reader, RXingResult, RXingResultMetadataType, RXingResultMetadataValue, Reader,
}; };
@@ -151,7 +151,7 @@ pub struct RSSExpandedReader {
} }
impl AbstractRSSReaderTrait for RSSExpandedReader {} impl AbstractRSSReaderTrait for RSSExpandedReader {}
impl OneDReader for RSSExpandedReader { impl OneDReader for RSSExpandedReader {
fn decodeRow( fn decode_row(
&mut self, &mut self,
rowNumber: u32, rowNumber: u32,
row: &crate::common::BitArray, row: &crate::common::BitArray,
@@ -173,26 +173,26 @@ impl OneDReader for RSSExpandedReader {
} }
} }
impl Reader 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()) self.decode_with_hints(image, &HashMap::new())
} }
// Note that we don't try rotation without the try harder flag, even if rotation was supported. // 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, &mut self,
image: &mut crate::BinaryBitmap, image: &mut crate::BinaryBitmap<B>,
hints: &DecodingHintDictionary, hints: &DecodingHintDictionary,
) -> Result<crate::RXingResult> { ) -> Result<crate::RXingResult> {
if let Ok(res) = self.doDecode(image, hints) { if let Ok(res) = self._do_decode(image, hints) {
Ok(res) Ok(res)
} else { } else {
let tryHarder = matches!( let tryHarder = matches!(
hints.get(&DecodeHintType::TRY_HARDER), hints.get(&DecodeHintType::TRY_HARDER),
Some(DecodeHintValue::TryHarder(true)) Some(DecodeHintValue::TryHarder(true))
); );
if tryHarder && image.isRotateSupported() { if tryHarder && image.is_rotate_supported() {
let mut rotatedImage = image.rotateCounterClockwise(); let mut rotatedImage = image.rotate_counter_clockwise();
let mut result = self.doDecode(&mut rotatedImage, hints)?; let mut result = self._do_decode(&mut rotatedImage, hints)?;
// Record that we found it rotated 90 degrees CCW / 270 degrees CW // Record that we found it rotated 90 degrees CCW / 270 degrees CW
let metadata = result.getRXingResultMetadata(); let metadata = result.getRXingResultMetadata();
let mut orientation = 270; let mut orientation = 270;
@@ -213,7 +213,7 @@ impl Reader for RSSExpandedReader {
RXingResultMetadataValue::Orientation(orientation), RXingResultMetadataValue::Orientation(orientation),
); );
// Update result points // Update result points
let height = rotatedImage.getHeight(); let height = rotatedImage.get_height();
let total_points = result.getPoints().len(); let total_points = result.getPoints().len();
let points = result.getPointsMut(); let points = result.getPointsMut();
@@ -684,7 +684,7 @@ impl RSSExpandedReader {
// counters[2] = 0; // counters[2] = 0;
// counters[3] = 0; // counters[3] = 0;
let width = row.getSize(); let width = row.get_size();
let mut rowOffset; let mut rowOffset;
if forcedOffset >= 0 { if forcedOffset >= 0 {
@@ -823,9 +823,9 @@ impl RSSExpandedReader {
counters.fill(0); counters.fill(0);
if leftChar { if leftChar {
recordPatternInReverse(row, pattern.getStartEnd()[0], counters)?; record_pattern_in_reverse(row, pattern.getStartEnd()[0], counters)?;
} else { } else {
recordPattern(row, pattern.getStartEnd()[1], counters)?; record_pattern(row, pattern.getStartEnd()[1], counters)?;
// reverse it // reverse it
counters.reverse(); counters.reverse();
// let mut i = 0; // let mut i = 0;

View File

@@ -39,8 +39,8 @@ fn testDecodingRowByRow() {
let binaryMap = test_case_util::getBinaryBitmap("1000.png"); let binaryMap = test_case_util::getBinaryBitmap("1000.png");
let firstRowNumber = binaryMap.getHeight() / 3; let firstRowNumber = binaryMap.get_height() / 3;
let firstRow = binaryMap.getBlackRow(firstRowNumber).expect("get row"); let firstRow = binaryMap.get_black_row(firstRowNumber).expect("get row");
// let tester = ; // let tester = ;
@@ -72,9 +72,9 @@ fn testDecodingRowByRow() {
.unwrap() .unwrap()
.getStartEndMut()[1] = 0; .getStartEndMut()[1] = 0;
let secondRowNumber = 2 * binaryMap.getHeight() / 3; let secondRowNumber = 2 * binaryMap.get_height() / 3;
let mut secondRow = binaryMap let mut secondRow = binaryMap
.getBlackRow(secondRowNumber) .get_black_row(secondRowNumber)
.expect("get row") .expect("get row")
.into_owned(); .into_owned();

View File

@@ -19,8 +19,8 @@ use std::collections::HashMap;
use crate::{ use crate::{
common::{BitArray, Result}, common::{BitArray, Result},
oned::{one_d_reader, OneDReader}, oned::{one_d_reader, OneDReader},
point, BarcodeFormat, DecodeHintType, DecodeHintValue, DecodingHintDictionary, Exceptions, point, BarcodeFormat, Binarizer, DecodeHintType, DecodeHintValue, DecodingHintDictionary,
RXingResult, RXingResultMetadataType, RXingResultMetadataValue, Reader, Exceptions, RXingResult, RXingResultMetadataType, RXingResultMetadataValue, Reader,
}; };
use super::{ use super::{
@@ -45,12 +45,12 @@ pub struct RSS14Reader {
impl AbstractRSSReaderTrait for RSS14Reader {} impl AbstractRSSReaderTrait for RSS14Reader {}
impl OneDReader for RSS14Reader { impl OneDReader for RSS14Reader {
fn decodeRow( fn decode_row(
&mut self, &mut self,
rowNumber: u32, rowNumber: u32,
row: &crate::common::BitArray, row: &BitArray,
hints: &crate::DecodingHintDictionary, hints: &DecodingHintDictionary,
) -> Result<crate::RXingResult> { ) -> Result<RXingResult> {
let mut row = row.clone(); let mut row = row.clone();
let leftPair = self.decodePair(&row, false, rowNumber, hints); let leftPair = self.decodePair(&row, false, rowNumber, hints);
Self::addOrTally(&mut self.possibleLeftPairs, leftPair); Self::addOrTally(&mut self.possibleLeftPairs, leftPair);
@@ -73,26 +73,26 @@ impl OneDReader for RSS14Reader {
} }
} }
impl Reader 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()) self.decode_with_hints(image, &HashMap::new())
} }
// Note that we don't try rotation without the try harder flag, even if rotation was supported. // 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, &mut self,
image: &mut crate::BinaryBitmap, image: &mut crate::BinaryBitmap<B>,
hints: &DecodingHintDictionary, hints: &DecodingHintDictionary,
) -> Result<crate::RXingResult> { ) -> Result<crate::RXingResult> {
if let Ok(res) = self.doDecode(image, hints) { if let Ok(res) = self._do_decode(image, hints) {
Ok(res) Ok(res)
} else { } else {
let tryHarder = matches!( let tryHarder = matches!(
hints.get(&DecodeHintType::TRY_HARDER), hints.get(&DecodeHintType::TRY_HARDER),
Some(DecodeHintValue::TryHarder(true)) Some(DecodeHintValue::TryHarder(true))
); );
if tryHarder && image.isRotateSupported() { if tryHarder && image.is_rotate_supported() {
let mut rotatedImage = image.rotateCounterClockwise(); let mut rotatedImage = image.rotate_counter_clockwise();
let mut result = self.doDecode(&mut rotatedImage, hints)?; let mut result = self._do_decode(&mut rotatedImage, hints)?;
// Record that we found it rotated 90 degrees CCW / 270 degrees CW // Record that we found it rotated 90 degrees CCW / 270 degrees CW
let metadata = result.getRXingResultMetadata(); let metadata = result.getRXingResultMetadata();
let mut orientation = 270; let mut orientation = 270;
@@ -113,7 +113,7 @@ impl Reader for RSS14Reader {
RXingResultMetadataValue::Orientation(orientation), RXingResultMetadataValue::Orientation(orientation),
); );
// Update result points // Update result points
let height = rotatedImage.getHeight(); let height = rotatedImage.get_height();
let total_points = result.getPoints().len(); let total_points = result.getPoints().len();
let points = result.getPointsMut(); let points = result.getPointsMut();
for point in points.iter_mut().take(total_points) { 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; let mut center: f32 = (startEnd[0] + startEnd[1] - 1) as f32 / 2.0;
if right { if right {
// row is actually reversed // 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)); cb(point(center, rowNumber as f32));
} }
@@ -287,9 +287,9 @@ impl RSS14Reader {
counters.fill(0); counters.fill(0);
if outsideChar { if outsideChar {
one_d_reader::recordPatternInReverse(row, pattern.getStartEnd()[0], counters)?; one_d_reader::record_pattern_in_reverse(row, pattern.getStartEnd()[0], counters)?;
} else { } else {
one_d_reader::recordPattern(row, pattern.getStartEnd()[1], counters)?; one_d_reader::record_pattern(row, pattern.getStartEnd()[1], counters)?;
// reverse it // reverse it
counters.reverse(); counters.reverse();
// let mut i = 0; // let mut i = 0;
@@ -379,7 +379,7 @@ impl RSS14Reader {
let counters = &mut self.decodeFinderCounters; let counters = &mut self.decodeFinderCounters;
counters.fill(0); counters.fill(0);
let width = row.getSize(); let width = row.get_size();
let mut isWhite = false; let mut isWhite = false;
let mut rowOffset = 0; let mut rowOffset = 0;
while rowOffset < width { while rowOffset < width {
@@ -445,8 +445,8 @@ impl RSS14Reader {
let mut end = startEnd[1]; let mut end = startEnd[1];
if right { if right {
// row is actually reversed // row is actually reversed
start = row.getSize() - 1 - start; start = row.get_size() - 1 - start;
end = row.getSize() - 1 - end; end = row.get_size() - 1 - end;
} }
Ok(FinderPattern::new( Ok(FinderPattern::new(

View File

@@ -14,7 +14,7 @@
* limitations under the License. * 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}; use super::{EAN13Reader, OneDReader, UPCEANReader};
@@ -28,32 +28,50 @@ use super::{EAN13Reader, OneDReader, UPCEANReader};
pub struct UPCAReader(EAN13Reader); pub struct UPCAReader(EAN13Reader);
impl Reader for UPCAReader { 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)?) Self::maybeReturnRXingResult(self.0.decode(image)?)
} }
fn decode_with_hints( fn decode_with_hints<B: Binarizer>(
&mut self, &mut self,
image: &mut crate::BinaryBitmap, image: &mut crate::BinaryBitmap<B>,
hints: &crate::DecodingHintDictionary, hints: &crate::DecodingHintDictionary,
) -> Result<crate::RXingResult> { ) -> Result<RXingResult> {
Self::maybeReturnRXingResult(self.0.decode_with_hints(image, hints)?) Self::maybeReturnRXingResult(self.0.decode_with_hints(image, hints)?)
} }
} }
impl OneDReader for UPCAReader { impl OneDReader for UPCAReader {
fn decodeRow( fn decode_row(
&mut self, &mut self,
rowNumber: u32, rowNumber: u32,
row: &crate::common::BitArray, row: &crate::common::BitArray,
hints: &crate::DecodingHintDictionary, hints: &crate::DecodingHintDictionary,
) -> Result<crate::RXingResult> { ) -> Result<RXingResult> {
Self::maybeReturnRXingResult(self.0.decodeRow(rowNumber, row, hints)?) Self::maybeReturnRXingResult(self.0.decode_row(rowNumber, row, hints)?)
} }
} }
impl UPCEANReader for UPCAReader { 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 BarcodeFormat::UPC_A
} }
@@ -65,24 +83,6 @@ impl UPCEANReader for UPCAReader {
) -> Result<usize> { ) -> Result<usize> {
self.0.decodeMiddle(row, startRange, resultString) 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 { impl UPCAReader {

View File

@@ -41,7 +41,7 @@ impl UPCEANReader for UPCEReader {
) -> Result<usize> { ) -> Result<usize> {
let mut counters = [0_u32; 4]; let mut counters = [0_u32; 4];
let end = row.getSize(); let end = row.get_size();
let mut rowOffset = startRange[1]; let mut rowOffset = startRange[1];
let mut lgPatternFound = 0; let mut lgPatternFound = 0;

View File

@@ -73,7 +73,7 @@ impl UPCEANExtension2Support {
let mut counters = self.decodeMiddleCounters; let mut counters = self.decodeMiddleCounters;
counters.fill(0); counters.fill(0);
let end = row.getSize(); let end = row.get_size();
let mut rowOffset = startRange[1] as usize; let mut rowOffset = startRange[1] as usize;
let mut checkParity = 0; let mut checkParity = 0;

View File

@@ -73,7 +73,7 @@ impl UPCEANExtension5Support {
resultString: &mut String, resultString: &mut String,
) -> Result<u32> { ) -> Result<u32> {
let mut counters = [0_u32; 4]; let mut counters = [0_u32; 4];
let end = row.getSize(); let end = row.get_size();
let mut rowOffset = startRange[1]; let mut rowOffset = startRange[1];
let mut lgPatternFound = 0; let mut lgPatternFound = 0;

View File

@@ -16,7 +16,7 @@
use crate::{ use crate::{
common::{BitArray, Result}, common::{BitArray, Result},
point, BarcodeFormat, DecodeHintType, DecodeHintValue, Exceptions, RXingResult, point, BarcodeFormat, Binarizer, DecodeHintType, DecodeHintValue, Exceptions, RXingResult,
RXingResultMetadataType, RXingResultMetadataValue, Reader, RXingResultMetadataType, RXingResultMetadataValue, Reader,
}; };
@@ -101,7 +101,7 @@ pub const L_AND_G_PATTERNS: [[u32; 4]; 20] = {
* @author alasdair@google.com (Alasdair Mackintosh) * @author alasdair@google.com (Alasdair Mackintosh)
*/ */
pub trait UPCEANReader: OneDReader { 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 foundStart = false;
let mut startRange = [0; 2]; let mut startRange = [0; 2];
let mut nextStart = 0; 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. // spec might want more whitespace, but in practice this is the maximum we can count on.
let end = endRange[1]; let end = endRange[1];
let quietEnd = end + (end - endRange[0]); 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); return Err(Exceptions::NOT_FOUND);
} }
@@ -382,7 +382,7 @@ pub trait UPCEANReader: OneDReader {
pattern: &[u32], pattern: &[u32],
counters: &mut [u32], counters: &mut [u32],
) -> Result<[usize; 2]> { ) -> Result<[usize; 2]> {
let width = row.getSize(); let width = row.get_size();
let rowOffset = if whiteFirst { let rowOffset = if whiteFirst {
row.getNextUnset(rowOffset) row.getNextUnset(rowOffset)
} else { } else {
@@ -398,7 +398,7 @@ pub trait UPCEANReader: OneDReader {
counters[counterPosition] += 1; counters[counterPosition] += 1;
} else { } else {
if counterPosition == patternLength - 1 { if counterPosition == patternLength - 1 {
if one_d_reader::patternMatchVariance( if one_d_reader::pattern_match_variance(
counters, counters,
pattern, pattern,
MAX_INDIVIDUAL_VARIANCE, MAX_INDIVIDUAL_VARIANCE,
@@ -443,13 +443,13 @@ pub trait UPCEANReader: OneDReader {
rowOffset: usize, rowOffset: usize,
patterns: &[[u32; 4]], patterns: &[[u32; 4]],
) -> Result<usize> { ) -> 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 bestVariance = MAX_AVG_VARIANCE; // worst variance we'll accept
let mut bestMatch = -1_isize; let mut bestMatch = -1_isize;
let max = patterns.len(); let max = patterns.len();
for (i, pattern) in patterns.iter().enumerate().take(max) { for (i, pattern) in patterns.iter().enumerate().take(max) {
let variance: f32 = 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 { if variance < bestVariance {
bestVariance = variance; bestVariance = variance;
bestMatch = i as isize; bestMatch = i as isize;
@@ -503,7 +503,7 @@ impl UPCEANReader for StandInStruct {
} }
} }
impl OneDReader for StandInStruct { impl OneDReader for StandInStruct {
fn decodeRow( fn decode_row(
&mut self, &mut self,
_rowNumber: u32, _rowNumber: u32,
_row: &BitArray, _row: &BitArray,
@@ -514,13 +514,13 @@ impl OneDReader for StandInStruct {
} }
impl Reader 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!() todo!()
} }
fn decode_with_hints( fn decode_with_hints<B: Binarizer>(
&mut self, &mut self,
_image: &mut crate::BinaryBitmap, _image: &mut crate::BinaryBitmap<B>,
_hints: &crate::DecodingHintDictionary, _hints: &crate::DecodingHintDictionary,
) -> Result<RXingResult> { ) -> Result<RXingResult> {
todo!() todo!()

View File

@@ -16,7 +16,7 @@
use crate::{ use crate::{
common::{BitMatrix, Result}, common::{BitMatrix, Result},
point, BinaryBitmap, DecodingHintDictionary, Exceptions, Point, point, Binarizer, BinaryBitmap, DecodingHintDictionary, Exceptions, Point,
}; };
use std::borrow::Cow; 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 * @return {@link PDF417DetectorRXingResult} encapsulating results of detecting a PDF417 code
* @throws NotFoundException if no PDF417 Code can be found * @throws NotFoundException if no PDF417 Code can be found
*/ */
pub fn detect_with_hints( pub fn detect_with_hints<B: Binarizer>(
image: &mut BinaryBitmap, image: &mut BinaryBitmap<B>,
_hints: &DecodingHintDictionary, _hints: &DecodingHintDictionary,
multiple: bool, multiple: bool,
) -> Result<PDF417DetectorRXingResult> { ) -> Result<PDF417DetectorRXingResult> {
@@ -74,7 +74,7 @@ pub fn detect_with_hints(
//boolean tryHarder = hints != null && hints.containsKey(DecodeHintType.TRY_HARDER); //boolean tryHarder = hints != null && hints.containsKey(DecodeHintType.TRY_HARDER);
//let try_harder = matches!(hints.get(&DecodeHintType::TRY_HARDER), Some(DecodeHintValue::TryHarder(true))); //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 rotation in ROTATIONS {
// for (int rotation : ROTATIONS) { // for (int rotation : ROTATIONS) {
let bitMatrix = applyRotation(originalMatrix, rotation)?; let bitMatrix = applyRotation(originalMatrix, rotation)?;

View File

@@ -17,7 +17,7 @@
use std::collections::HashMap; use std::collections::HashMap;
use crate::{ use crate::{
common::Result, multi::MultipleBarcodeReader, BarcodeFormat, BinaryBitmap, common::Result, multi::MultipleBarcodeReader, BarcodeFormat, Binarizer, BinaryBitmap,
DecodingHintDictionary, Exceptions, Point, RXingResult, RXingResultMetadataType, DecodingHintDictionary, Exceptions, Point, RXingResult, RXingResultMetadataType,
RXingResultMetadataValue, Reader, RXingResultMetadataValue, Reader,
}; };
@@ -43,13 +43,13 @@ impl Reader for PDF417Reader {
* @throws NotFoundException if a PDF417 code cannot be found, * @throws NotFoundException if a PDF417 code cannot be found,
* @throws FormatException if a PDF417 cannot be decoded * @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()) self.decode_with_hints(image, &HashMap::new())
} }
fn decode_with_hints( fn decode_with_hints<B: Binarizer>(
&mut self, &mut self,
image: &mut crate::BinaryBitmap, image: &mut BinaryBitmap<B>,
hints: &crate::DecodingHintDictionary, hints: &crate::DecodingHintDictionary,
) -> Result<crate::RXingResult> { ) -> Result<crate::RXingResult> {
let result = Self::decode(image, hints, false)?; let result = Self::decode(image, hints, false)?;
@@ -61,18 +61,18 @@ impl Reader for PDF417Reader {
} }
impl MultipleBarcodeReader for PDF417Reader { impl MultipleBarcodeReader for PDF417Reader {
fn decode_multiple( fn decode_multiple<B: Binarizer>(
&mut self, &mut self,
image: &mut crate::BinaryBitmap, image: &mut BinaryBitmap<B>,
) -> Result<Vec<crate::RXingResult>> { ) -> Result<Vec<RXingResult>> {
self.decode_multiple_with_hints(image, &HashMap::new()) self.decode_multiple_with_hints(image, &HashMap::new())
} }
fn decode_multiple_with_hints( fn decode_multiple_with_hints<B: Binarizer>(
&mut self, &mut self,
image: &mut crate::BinaryBitmap, image: &mut BinaryBitmap<B>,
hints: &crate::DecodingHintDictionary, hints: &DecodingHintDictionary,
) -> Result<Vec<crate::RXingResult>> { ) -> Result<Vec<RXingResult>> {
Self::decode(image, hints, true) Self::decode(image, hints, true)
} }
} }
@@ -82,8 +82,8 @@ impl PDF417Reader {
Self::default() Self::default()
} }
fn decode( fn decode<B: Binarizer>(
image: &mut BinaryBitmap, image: &mut BinaryBitmap<B>,
hints: &DecodingHintDictionary, hints: &DecodingHintDictionary,
multiple: bool, multiple: bool,
) -> Result<Vec<RXingResult>> { ) -> Result<Vec<RXingResult>> {

View File

@@ -191,8 +191,8 @@ impl PlanarYUVLuminanceSource {
} }
pub fn renderThumbnail(&self) -> Vec<u8> { pub fn renderThumbnail(&self) -> Vec<u8> {
let width = self.getWidth() / THUMBNAIL_SCALE_FACTOR; let width = self.get_width() / THUMBNAIL_SCALE_FACTOR;
let height = self.getHeight() / THUMBNAIL_SCALE_FACTOR; let height = self.get_height() / THUMBNAIL_SCALE_FACTOR;
let mut pixels = vec![0; width * height]; let mut pixels = vec![0; width * height];
let yuv = &self.yuv_data; let yuv = &self.yuv_data;
let mut input_offset = self.top * self.data_width + self.left; let mut input_offset = self.top * self.data_width + self.left;
@@ -212,14 +212,14 @@ impl PlanarYUVLuminanceSource {
* @return width of image from {@link #renderThumbnail()} * @return width of image from {@link #renderThumbnail()}
*/ */
pub fn getThumbnailWidth(&self) -> usize { pub fn getThumbnailWidth(&self) -> usize {
self.getWidth() / THUMBNAIL_SCALE_FACTOR self.get_width() / THUMBNAIL_SCALE_FACTOR
} }
/** /**
* @return height of image from {@link #renderThumbnail()} * @return height of image from {@link #renderThumbnail()}
*/ */
pub fn getThumbnailHeight(&self) -> usize { pub fn getThumbnailHeight(&self) -> usize {
self.getHeight() / THUMBNAIL_SCALE_FACTOR self.get_height() / THUMBNAIL_SCALE_FACTOR
} }
fn reverseHorizontal(&mut self, width: usize, height: usize) { fn reverseHorizontal(&mut self, width: usize, height: usize) {
@@ -237,13 +237,13 @@ impl PlanarYUVLuminanceSource {
} }
impl LuminanceSource for PlanarYUVLuminanceSource { impl LuminanceSource for PlanarYUVLuminanceSource {
fn getRow(&self, y: usize) -> Vec<u8> { fn get_row(&self, y: usize) -> Vec<u8> {
if y >= self.getHeight() { if y >= self.get_height() {
// //throw new IllegalArgumentException("Requested row is outside the image: " + y); // //throw new IllegalArgumentException("Requested row is outside the image: " + y);
// panic!("Requested row is outside the image: {y}"); // panic!("Requested row is outside the image: {y}");
return Vec::new(); return Vec::new();
} }
let width = self.getWidth(); let width = self.get_width();
let offset = (y + self.top) * self.data_width + self.left; let offset = (y + self.top) * self.data_width + self.left;
@@ -256,9 +256,9 @@ impl LuminanceSource for PlanarYUVLuminanceSource {
row row
} }
fn getMatrix(&self) -> Vec<u8> { fn get_matrix(&self) -> Vec<u8> {
let width = self.getWidth(); let width = self.get_width();
let height = self.getHeight(); let height = self.get_height();
// If the caller asks for the entire underlying image, save the copy and give them the // 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. // original data. The docs specifically warn that result.length must be ignored.
@@ -298,26 +298,20 @@ impl LuminanceSource for PlanarYUVLuminanceSource {
matrix matrix
} }
fn getWidth(&self) -> usize { fn get_width(&self) -> usize {
self.width self.width
} }
fn getHeight(&self) -> usize { fn get_height(&self) -> usize {
self.height self.height
} }
fn isCropSupported(&self) -> bool { fn is_crop_supported(&self) -> bool {
true true
} }
fn crop( fn crop(&self, left: usize, top: usize, width: usize, height: usize) -> Result<Self> {
&self, PlanarYUVLuminanceSource::new_with_all(
left: usize,
top: usize,
width: usize,
height: usize,
) -> Result<Box<dyn LuminanceSource>> {
match PlanarYUVLuminanceSource::new_with_all(
self.yuv_data.clone(), self.yuv_data.clone(),
self.data_width, self.data_width,
self.data_height, self.data_height,
@@ -327,13 +321,11 @@ impl LuminanceSource for PlanarYUVLuminanceSource {
height, height,
false, false,
self.invert, self.invert,
) { )
Ok(new) => Ok(Box::new(new)), .map_err(|_| Exceptions::UNSUPPORTED_OPERATION)
Err(_err) => Err(Exceptions::UNSUPPORTED_OPERATION),
}
} }
fn isRotateSupported(&self) -> bool { fn is_rotate_supported(&self) -> bool {
false false
} }

View File

@@ -39,43 +39,43 @@ fn testAppendBit() {
assert_eq!(0, v.getSizeInBytes()); assert_eq!(0, v.getSizeInBytes());
// 1 // 1
v.appendBit(true); v.appendBit(true);
assert_eq!(1, v.getSize()); assert_eq!(1, v.get_size());
assert_eq!(0x80000000, getUnsignedInt(&v)); assert_eq!(0x80000000, getUnsignedInt(&v));
// 10 // 10
v.appendBit(false); v.appendBit(false);
assert_eq!(2, v.getSize()); assert_eq!(2, v.get_size());
assert_eq!(0x80000000, getUnsignedInt(&v)); assert_eq!(0x80000000, getUnsignedInt(&v));
// 101 // 101
v.appendBit(true); v.appendBit(true);
assert_eq!(3, v.getSize()); assert_eq!(3, v.get_size());
assert_eq!(0xa0000000, getUnsignedInt(&v)); assert_eq!(0xa0000000, getUnsignedInt(&v));
// 1010 // 1010
v.appendBit(false); v.appendBit(false);
assert_eq!(4, v.getSize()); assert_eq!(4, v.get_size());
assert_eq!(0xa0000000, getUnsignedInt(&v)); assert_eq!(0xa0000000, getUnsignedInt(&v));
// 10101 // 10101
v.appendBit(true); v.appendBit(true);
assert_eq!(5, v.getSize()); assert_eq!(5, v.get_size());
assert_eq!(0xa8000000, getUnsignedInt(&v)); assert_eq!(0xa8000000, getUnsignedInt(&v));
// 101010 // 101010
v.appendBit(false); v.appendBit(false);
assert_eq!(6, v.getSize()); assert_eq!(6, v.get_size());
assert_eq!(0xa8000000, getUnsignedInt(&v)); assert_eq!(0xa8000000, getUnsignedInt(&v));
// 1010101 // 1010101
v.appendBit(true); v.appendBit(true);
assert_eq!(7, v.getSize()); assert_eq!(7, v.get_size());
assert_eq!(0xaa000000, getUnsignedInt(&v)); assert_eq!(0xaa000000, getUnsignedInt(&v));
// 10101010 // 10101010
v.appendBit(false); v.appendBit(false);
assert_eq!(8, v.getSize()); assert_eq!(8, v.get_size());
assert_eq!(0xaa000000, getUnsignedInt(&v)); assert_eq!(0xaa000000, getUnsignedInt(&v));
// 10101010 1 // 10101010 1
v.appendBit(true); v.appendBit(true);
assert_eq!(9, v.getSize()); assert_eq!(9, v.get_size());
assert_eq!(0xaa800000, getUnsignedInt(&v)); assert_eq!(0xaa800000, getUnsignedInt(&v));
// 10101010 10 // 10101010 10
v.appendBit(false); v.appendBit(false);
assert_eq!(10, v.getSize()); assert_eq!(10, v.get_size());
assert_eq!(0xaa800000, getUnsignedInt(&v)); assert_eq!(0xaa800000, getUnsignedInt(&v));
} }
@@ -83,15 +83,15 @@ fn testAppendBit() {
fn testAppendBits() { fn testAppendBits() {
let mut v = BitArray::new(); let mut v = BitArray::new();
v.appendBits(0x1, 1).expect("append"); v.appendBits(0x1, 1).expect("append");
assert_eq!(1, v.getSize()); assert_eq!(1, v.get_size());
assert_eq!(0x80000000, getUnsignedInt(&v)); assert_eq!(0x80000000, getUnsignedInt(&v));
let mut v = BitArray::new(); let mut v = BitArray::new();
v.appendBits(0xff, 8).expect("append"); v.appendBits(0xff, 8).expect("append");
assert_eq!(8, v.getSize()); assert_eq!(8, v.get_size());
assert_eq!(0xff000000, getUnsignedInt(&v)); assert_eq!(0xff000000, getUnsignedInt(&v));
let mut v = BitArray::new(); let mut v = BitArray::new();
v.appendBits(0xff7, 12).expect("append"); v.appendBits(0xff7, 12).expect("append");
assert_eq!(12, v.getSize()); assert_eq!(12, v.get_size());
assert_eq!(0xff700000, getUnsignedInt(&v)); assert_eq!(0xff700000, getUnsignedInt(&v));
} }

View File

@@ -174,11 +174,11 @@ pub fn embedTypeInfo(
for (i, coordinates) in TYPE_INFO_COORDINATES for (i, coordinates) in TYPE_INFO_COORDINATES
.iter() .iter()
.enumerate() .enumerate()
.take(typeInfoBits.getSize()) .take(typeInfoBits.get_size())
{ {
// Place bits in LSB to MSB order. LSB (least significant bit) is the last value in // Place bits in LSB to MSB order. LSB (least significant bit) is the last value in
// "typeInfoBits". // "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). // Type info bits at the left top corner. See 8.9 of JISX0510:2004 (p.46).
// let coordinates = TYPE_INFO_COORDINATES[i]; // let coordinates = TYPE_INFO_COORDINATES[i];
@@ -249,7 +249,7 @@ pub fn embedDataBits(dataBits: &BitArray, maskPattern: i32, matrix: &mut ByteMat
continue; continue;
} }
let mut bit; let mut bit;
if bitIndex < dataBits.getSize() { if bitIndex < dataBits.get_size() {
bit = dataBits.get(bitIndex); bit = dataBits.get(bitIndex);
bitIndex += 1; bitIndex += 1;
} else { } else {
@@ -273,11 +273,11 @@ pub fn embedDataBits(dataBits: &BitArray, maskPattern: i32, matrix: &mut ByteMat
x -= 2; // Move to the left. x -= 2; // Move to the left.
} }
// All bits should be consumed. // All bits should be consumed.
if bitIndex != dataBits.getSize() { if bitIndex != dataBits.get_size() {
return Err(Exceptions::writer_with(format!( return Err(Exceptions::writer_with(format!(
"Not all bits consumed: {}/{}", "Not all bits consumed: {}/{}",
bitIndex, bitIndex,
dataBits.getSize() dataBits.get_size()
))); )));
} }
Ok(()) Ok(())
@@ -355,11 +355,11 @@ pub fn makeTypeInfoBits(
maskBits.appendBits(TYPE_INFO_MASK_PATTERN, 15)?; maskBits.appendBits(TYPE_INFO_MASK_PATTERN, 15)?;
bits.xor(&maskBits)?; bits.xor(&maskBits)?;
if bits.getSize() != 15 { if bits.get_size() != 15 {
// Just in case. // Just in case.
return Err(Exceptions::writer_with(format!( return Err(Exceptions::writer_with(format!(
"should not happen but we got: {}", "should not happen but we got: {}",
bits.getSize() bits.get_size()
))); )));
} }
Ok(()) Ok(())
@@ -372,11 +372,11 @@ pub fn makeVersionInfoBits(version: &Version, bits: &mut BitArray) -> Result<()>
let bchCode = calculateBCHCode(version.getVersionNumber(), VERSION_INFO_POLY)?; let bchCode = calculateBCHCode(version.getVersionNumber(), VERSION_INFO_POLY)?;
bits.appendBits(bchCode, 12)?; bits.appendBits(bchCode, 12)?;
if bits.getSize() != 18 { if bits.get_size() != 18 {
// Just in case. // Just in case.
return Err(Exceptions::writer_with(format!( return Err(Exceptions::writer_with(format!(
"should not happen but we got: {}", "should not happen but we got: {}",
bits.getSize() bits.get_size()
))); )));
} }
Ok(()) Ok(())

View File

@@ -286,7 +286,7 @@ fn calculateBitsNeeded(
data_bits: &BitArray, data_bits: &BitArray,
version: VersionRef, version: VersionRef,
) -> u32 { ) -> 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 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<()> { pub fn terminateBits(num_data_bytes: u32, bits: &mut BitArray) -> Result<()> {
let capacity = num_data_bytes * 8; 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!( return Err(Exceptions::writer_with(format!(
"data bits cannot fit in the QR Code{capacity} > " "data bits cannot fit in the QR Code{capacity} > "
))); )));
} }
// Append Mode.TERMINATE if there is enough space (value is 0000) // Append Mode.TERMINATE if there is enough space (value is 0000)
for _i in 0..4 { for _i in 0..4 {
if bits.getSize() >= capacity as usize { if bits.get_size() >= capacity as usize {
break; break;
} }
bits.appendBit(false); bits.appendBit(false);
} }
// Append termination bits. See 8.4.8 of JISX0510:2004 (p.24) for details. // 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. // 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 { if num_bits_in_last_byte > 0 {
for _i in num_bits_in_last_byte..8 { for _i in num_bits_in_last_byte..8 {
bits.appendBit(false); 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)?; 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")); return Err(Exceptions::writer_with("Bits size does not equal capacity"));
} }
Ok(()) Ok(())

View File

@@ -18,7 +18,7 @@ use std::collections::HashMap;
use crate::{ use crate::{
common::{BitMatrix, DecoderRXingResult, DetectorRXingResult, Result}, common::{BitMatrix, DecoderRXingResult, DetectorRXingResult, Result},
BarcodeFormat, DecodeHintType, DecodeHintValue, Exceptions, Point, RXingResult, BarcodeFormat, Binarizer, DecodeHintType, DecodeHintValue, Exceptions, Point, RXingResult,
RXingResultMetadataType, RXingResultMetadataValue, Reader, RXingResultMetadataType, RXingResultMetadataValue, Reader,
}; };
@@ -48,27 +48,27 @@ impl Reader for QRCodeReader {
* @throws FormatException if a QR code cannot be decoded * @throws FormatException if a QR code cannot be decoded
* @throws ChecksumException if error correction fails * @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()) self.decode_with_hints(image, &HashMap::new())
} }
fn decode_with_hints( fn decode_with_hints<B: Binarizer>(
&mut self, &mut self,
image: &mut crate::BinaryBitmap, image: &mut crate::BinaryBitmap<B>,
hints: &crate::DecodingHintDictionary, hints: &crate::DecodingHintDictionary,
) -> Result<crate::RXingResult> { ) -> Result<RXingResult> {
let decoderRXingResult: DecoderRXingResult; let decoderRXingResult: DecoderRXingResult;
let mut points: Vec<Point>; let mut points: Vec<Point>;
if matches!( if matches!(
hints.get(&DecodeHintType::PURE_BARCODE), hints.get(&DecodeHintType::PURE_BARCODE),
Some(DecodeHintValue::PureBarcode(true)) 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)?; decoderRXingResult = qrcode_decoder::decode_bitmatrix_with_hints(&bits, hints)?;
points = Vec::new(); points = Vec::new();
} else { } else {
let detectorRXingResult = let detectorRXingResult =
Detector::new(image.getBlackMatrix()).detect_with_hints(hints)?; Detector::new(image.get_black_matrix()).detect_with_hints(hints)?;
decoderRXingResult = decoderRXingResult =
qrcode_decoder::decode_bitmatrix_with_hints(detectorRXingResult.getBits(), hints)?; qrcode_decoder::decode_bitmatrix_with_hints(detectorRXingResult.getBits(), hints)?;
points = detectorRXingResult.getPoints().to_vec(); points = detectorRXingResult.getPoints().to_vec();

View File

@@ -16,7 +16,7 @@
//package com.google.zxing; //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 * 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 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 * @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 * 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 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 * @throws FormatException if a potential barcode is found but format is invalid
*/ */
fn decode_with_hints( fn decode_with_hints<B: Binarizer>(
&mut self, &mut self,
image: &mut BinaryBitmap, image: &mut BinaryBitmap<B>,
hints: &DecodingHintDictionary, hints: &DecodingHintDictionary,
) -> Result<RXingResult>; ) -> Result<RXingResult>;

View File

@@ -40,11 +40,11 @@ pub struct RGBLuminanceSource {
impl LuminanceSource for RGBLuminanceSource { impl LuminanceSource for RGBLuminanceSource {
/// gets a row, returns an empty row if we are out of bounds. /// gets a row, returns an empty row if we are out of bounds.
fn getRow(&self, y: usize) -> Vec<u8> { fn get_row(&self, y: usize) -> Vec<u8> {
if y >= self.getHeight() { if y >= self.get_height() {
return Vec::new(); return Vec::new();
} }
let width = self.getWidth(); let width = self.get_width();
let offset = (y + self.top) * self.dataWidth + self.left; let offset = (y + self.top) * self.dataWidth + self.left;
@@ -58,9 +58,9 @@ impl LuminanceSource for RGBLuminanceSource {
row row
} }
fn getMatrix(&self) -> Vec<u8> { fn get_matrix(&self) -> Vec<u8> {
let width = self.getWidth(); let width = self.get_width();
let height = self.getHeight(); let height = self.get_height();
// If the caller asks for the entire underlying image, save the copy and give them the // 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. // original data. The docs specifically warn that result.length must be ignored.
@@ -99,26 +99,20 @@ impl LuminanceSource for RGBLuminanceSource {
matrix matrix
} }
fn getWidth(&self) -> usize { fn get_width(&self) -> usize {
self.width self.width
} }
fn getHeight(&self) -> usize { fn get_height(&self) -> usize {
self.height self.height
} }
fn isCropSupported(&self) -> bool { fn is_crop_supported(&self) -> bool {
true true
} }
fn crop( fn crop(&self, left: usize, top: usize, width: usize, height: usize) -> Result<Self> {
&self, RGBLuminanceSource::new_complex(
left: usize,
top: usize,
width: usize,
height: usize,
) -> Result<Box<dyn LuminanceSource>> {
match RGBLuminanceSource::new_complex(
&self.luminances, &self.luminances,
self.dataWidth, self.dataWidth,
self.dataHeight, self.dataHeight,
@@ -126,10 +120,8 @@ impl LuminanceSource for RGBLuminanceSource {
self.top + top, self.top + top,
width, width,
height, height,
) { )
Ok(crop) => Ok(Box::new(crop)), .map_err(|_| Exceptions::UNSUPPORTED_OPERATION)
Err(_error) => Err(Exceptions::UNSUPPORTED_OPERATION),
}
} }
fn invert(&mut self) { fn invert(&mut self) {

View File

@@ -34,11 +34,11 @@ const SRC_DATA: [u32; 9] = [
fn testCrop() { fn testCrop() {
let SOURCE = RGBLuminanceSource::new_with_width_height_pixels(3, 3, SRC_DATA.as_ref()); 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(); let cropped = SOURCE.crop(1, 1, 1, 1).unwrap();
assert_eq!(1, cropped.getHeight()); assert_eq!(1, cropped.get_height());
assert_eq!(1, cropped.getWidth()); assert_eq!(1, cropped.get_width());
assert_eq!(vec![0x7F], cropped.getRow(0)); assert_eq!(vec![0x7F], cropped.get_row(0));
} }
#[test] #[test]
@@ -47,22 +47,22 @@ fn testMatrix() {
assert_eq!( assert_eq!(
vec![0x00, 0x7F, 0xFF, 0x3F, 0x7F, 0x3F, 0x3F, 0x7F, 0x3F], vec![0x00, 0x7F, 0xFF, 0x3F, 0x7F, 0x3F, 0x3F, 0x7F, 0x3F],
SOURCE.getMatrix() SOURCE.get_matrix()
); );
let croppedFullWidth = SOURCE.crop(0, 1, 3, 2).unwrap(); let croppedFullWidth = SOURCE.crop(0, 1, 3, 2).unwrap();
assert_eq!( assert_eq!(
vec![0x3F, 0x7F, 0x3F, 0x3F, 0x7F, 0x3F], vec![0x3F, 0x7F, 0x3F, 0x3F, 0x7F, 0x3F],
croppedFullWidth.getMatrix() croppedFullWidth.get_matrix()
); );
let croppedCorner = SOURCE.crop(1, 1, 2, 2).unwrap(); 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] #[test]
fn testGetRow() { fn testGetRow() {
let SOURCE = RGBLuminanceSource::new_with_width_height_pixels(3, 3, SRC_DATA.as_ref()); 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] // #[test]

View File

@@ -6,28 +6,28 @@ use resvg::{self, usvg::Options};
pub struct SVGLuminanceSource(BufferedImageLuminanceSource); pub struct SVGLuminanceSource(BufferedImageLuminanceSource);
impl LuminanceSource for SVGLuminanceSource { impl LuminanceSource for SVGLuminanceSource {
fn getRow(&self, y: usize) -> Vec<u8> { fn get_row(&self, y: usize) -> Vec<u8> {
self.0.getRow(y) self.0.get_row(y)
} }
fn getMatrix(&self) -> Vec<u8> { fn get_matrix(&self) -> Vec<u8> {
self.0.getMatrix() self.0.get_matrix()
} }
fn getWidth(&self) -> usize { fn get_width(&self) -> usize {
self.0.getWidth() self.0.get_width()
} }
fn getHeight(&self) -> usize { fn get_height(&self) -> usize {
self.0.getHeight() self.0.get_height()
} }
fn invert(&mut self) { fn invert(&mut self) {
self.0.invert() self.0.invert()
} }
fn isCropSupported(&self) -> bool { fn is_crop_supported(&self) -> bool {
self.0.isCropSupported() self.0.is_crop_supported()
} }
fn crop( fn crop(
@@ -40,16 +40,16 @@ impl LuminanceSource for SVGLuminanceSource {
self.0.crop(left, top, width, height) self.0.crop(left, top, width, height)
} }
fn isRotateSupported(&self) -> bool { fn is_rotate_supported(&self) -> bool {
self.0.isRotateSupported() self.0.is_rotate_supported()
} }
fn rotateCounterClockwise(&self) -> Result<Box<dyn LuminanceSource>> { fn rotate_counter_clockwise(&self) -> Result<Box<dyn LuminanceSource>> {
self.0.rotateCounterClockwise() self.0.rotate_counter_clockwise()
} }
fn rotateCounterClockwise45(&self) -> Result<Box<dyn LuminanceSource>> { fn rotate_counter_clockwise_45(&self) -> Result<Box<dyn LuminanceSource>> {
self.0.rotateCounterClockwise45() self.0.rotate_counter_clockwise_45()
} }
} }