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

View File

@@ -52,10 +52,10 @@ fn test_no_crop() {
false,
)
.unwrap();
assert_equals(&Y, 0, &source.getMatrix(), 0, Y.len());
assert_equals(&Y, 0, &source.get_matrix(), 0, Y.len());
for r in 0..ROWS {
// for (int r = 0; r < ROWS; r++) {
assert_equals(&Y, r * COLS, &source.getRow(r), 0, COLS);
assert_equals(&Y, r * COLS, &source.get_row(r), 0, COLS);
}
}
@@ -73,8 +73,8 @@ fn test_crop() {
false,
)
.unwrap();
assert!(source.isCropSupported());
let cropMatrix = source.getMatrix();
assert!(source.is_crop_supported());
let cropMatrix = source.get_matrix();
for r in 0..ROWS - 2 {
// for (int r = 0; r < ROWS - 2; r++) {
assert_equals(
@@ -87,7 +87,7 @@ fn test_crop() {
}
for r in 0..ROWS - 2 {
// for (int r = 0; r < ROWS - 2; r++) {
assert_equals(&Y, (r + 1) * COLS + 1, &source.getRow(r), 0, COLS - 2);
assert_equals(&Y, (r + 1) * COLS + 1, &source.get_row(r), 0, COLS - 2);
}
}

View File

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

View File

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

View File

@@ -21,7 +21,7 @@ pub fn toBitArray(bits: &str) -> BitArray {
#[allow(dead_code)]
pub fn toBooleanArray(bitArray: &BitArray) -> Vec<bool> {
let mut result = vec![false; bitArray.getSize()];
let mut result = vec![false; bitArray.get_size()];
// for i in 0..result.len() {
for (i, res) in result.iter_mut().enumerate() {
// for (int i = 0; i < result.length; i++) {

View File

@@ -16,7 +16,7 @@
//package com.google.zxing;
use std::{borrow::Cow, rc::Rc};
use std::borrow::Cow;
use crate::{
common::{BitArray, BitMatrix, Result},
@@ -35,7 +35,9 @@ pub trait Binarizer {
//private final LuminanceSource source;
//fn new(source:dyn LuminanceSource) -> Self;
fn getLuminanceSource(&self) -> &Box<dyn LuminanceSource>;
type Source: LuminanceSource;
fn get_luminance_source(&self) -> &Self::Source;
/**
* Converts one row of luminance data to 1 bit data. May actually do the conversion, or return
@@ -51,7 +53,7 @@ pub trait Binarizer {
* @return The array of bits for this row (true means black).
* @throws NotFoundException if row can't be binarized
*/
fn getBlackRow(&self, y: usize) -> Result<Cow<BitArray>>;
fn get_black_row(&self, y: usize) -> Result<Cow<BitArray>>;
/**
* Converts a 2D array of luminance data to 1 bit data. As above, assume this method is expensive
@@ -62,7 +64,7 @@ pub trait Binarizer {
* @return The 2D array of bits for the image (true means black).
* @throws NotFoundException if image can't be binarized to make a matrix
*/
fn getBlackMatrix(&self) -> Result<&BitMatrix>;
fn get_black_matrix(&self) -> Result<&BitMatrix>;
/**
* Creates a new object with the same type as this Binarizer implementation, but with pristine
@@ -72,9 +74,11 @@ pub trait Binarizer {
* @param source The LuminanceSource this Binarizer will operate on.
* @return A new concrete Binarizer implementation object.
*/
fn createBinarizer(&self, source: Box<dyn LuminanceSource>) -> Rc<dyn Binarizer>;
fn create_binarizer(&self, source: Self::Source) -> Self
where
Self: Sized;
fn getWidth(&self) -> usize;
fn get_width(&self) -> usize;
fn getHeight(&self) -> usize;
fn get_height(&self) -> usize;
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -20,7 +20,7 @@
// import com.google.zxing.LuminanceSource;
// import com.google.zxing.NotFoundException;
use std::{borrow::Cow, rc::Rc};
use std::borrow::Cow;
use once_cell::unsync::OnceCell;
@@ -29,6 +29,10 @@ use crate::{Binarizer, Exceptions, LuminanceSource};
use super::{BitArray, BitMatrix};
const LUMINANCE_BITS: usize = 5;
const LUMINANCE_SHIFT: usize = 8 - LUMINANCE_BITS;
const LUMINANCE_BUCKETS: usize = 1 << LUMINANCE_BITS;
/**
* This Binarizer implementation uses the old ZXing global histogram approach. It is suitable
* for low-end mobile devices which don't have enough CPU or memory to use a local thresholding
@@ -40,34 +44,35 @@ use super::{BitArray, BitMatrix};
* @author dswitkin@google.com (Daniel Switkin)
* @author Sean Owen
*/
pub struct GlobalHistogramBinarizer {
pub struct GlobalHistogramBinarizer<LS: LuminanceSource> {
//_luminances: Vec<u8>,
width: usize,
height: usize,
source: Box<dyn LuminanceSource>,
source: LS,
black_matrix: OnceCell<BitMatrix>,
black_row_cache: Vec<OnceCell<BitArray>>,
}
impl Binarizer for GlobalHistogramBinarizer {
fn getLuminanceSource(&self) -> &Box<dyn LuminanceSource> {
impl<LS: LuminanceSource> Binarizer for GlobalHistogramBinarizer<LS> {
type Source = LS;
fn get_luminance_source(&self) -> &Self::Source {
&self.source
}
// Applies simple sharpening to the row data to improve performance of the 1D Readers.
fn getBlackRow(&self, y: usize) -> Result<Cow<BitArray>> {
fn get_black_row(&self, y: usize) -> Result<Cow<BitArray>> {
let row = self.black_row_cache[y].get_or_try_init(|| {
let source = self.getLuminanceSource();
let width = source.getWidth();
let source = self.get_luminance_source();
let width = source.get_width();
let mut row = BitArray::with_size(width);
// self.initArrays(width);
let localLuminances = source.getRow(y);
let mut localBuckets = [0; GlobalHistogramBinarizer::LUMINANCE_BUCKETS]; //self.buckets.clone();
let localLuminances = source.get_row(y);
let mut localBuckets = [0; LUMINANCE_BUCKETS]; //self.buckets.clone();
for x in 0..width {
// for (int x = 0; x < width; x++) {
localBuckets[((localLuminances[x]) >> GlobalHistogramBinarizer::LUMINANCE_SHIFT)
as usize] += 1;
localBuckets[((localLuminances[x]) >> LUMINANCE_SHIFT) as usize] += 1;
}
let blackPoint = Self::estimateBlackPoint(&localBuckets)?;
@@ -102,63 +107,60 @@ impl Binarizer for GlobalHistogramBinarizer {
}
// Does not sharpen the data, as this call is intended to only be used by 2D Readers.
fn getBlackMatrix(&self) -> Result<&BitMatrix> {
fn get_black_matrix(&self) -> Result<&BitMatrix> {
let matrix = self
.black_matrix
.get_or_try_init(|| Self::build_black_matrix(&self.source))?;
Ok(matrix)
}
fn createBinarizer(&self, source: Box<dyn crate::LuminanceSource>) -> Rc<dyn Binarizer> {
Rc::new(GlobalHistogramBinarizer::new(source))
fn create_binarizer(&self, source: LS) -> Self {
Self::new(source)
}
fn getWidth(&self) -> usize {
fn get_width(&self) -> usize {
self.width
}
fn getHeight(&self) -> usize {
fn get_height(&self) -> usize {
self.height
}
}
impl GlobalHistogramBinarizer {
const LUMINANCE_BITS: usize = 5;
const LUMINANCE_SHIFT: usize = 8 - GlobalHistogramBinarizer::LUMINANCE_BITS;
const LUMINANCE_BUCKETS: usize = 1 << GlobalHistogramBinarizer::LUMINANCE_BITS;
impl<LS: LuminanceSource> GlobalHistogramBinarizer<LS> {
// const EMPTY: [u8; 0] = [0; 0];
pub fn new(source: Box<dyn LuminanceSource>) -> Self {
pub fn new(source: LS) -> Self {
Self {
//_luminances: vec![0; source.getWidth()],
width: source.getWidth(),
height: source.getHeight(),
width: source.get_width(),
height: source.get_height(),
black_matrix: OnceCell::new(),
black_row_cache: vec![OnceCell::default(); source.getHeight()],
black_row_cache: vec![OnceCell::default(); source.get_height()],
source,
}
}
fn build_black_matrix(source: &Box<dyn LuminanceSource>) -> Result<BitMatrix> {
fn build_black_matrix(source: &LS) -> Result<BitMatrix> {
// let source = source.getLuminanceSource();
let width = source.getWidth();
let height = source.getHeight();
let width = source.get_width();
let height = source.get_height();
let mut matrix = BitMatrix::new(width as u32, height as u32)?;
// Quickly calculates the histogram by sampling four rows from the image. This proved to be
// more robust on the blackbox tests than sampling a diagonal as we used to do.
// self.initArrays(width);
let mut localBuckets = [0; GlobalHistogramBinarizer::LUMINANCE_BUCKETS]; //self.buckets.clone();
let mut localBuckets = [0; LUMINANCE_BUCKETS]; //self.buckets.clone();
for y in 1..5 {
// for (int y = 1; y < 5; y++) {
let row = height * y / 5;
let localLuminances = source.getRow(row);
let localLuminances = source.get_row(row);
let right = (width * 4) / 5;
let mut x = width / 5;
while x < right {
// for (int x = width / 5; x < right; x++) {
let pixel = localLuminances[x];
localBuckets[(pixel >> GlobalHistogramBinarizer::LUMINANCE_SHIFT) as usize] += 1;
localBuckets[(pixel >> LUMINANCE_SHIFT) as usize] += 1;
x += 1;
}
}
@@ -167,7 +169,7 @@ impl GlobalHistogramBinarizer {
// We delay reading the entire image luminance until the black point estimation succeeds.
// Although we end up reading four rows twice, it is consistent with our motto of
// "fail quickly" which is necessary for continuous scanning.
let localLuminances = source.getMatrix();
let localLuminances = source.get_matrix();
for y in 0..height {
// for (int y = 0; y < height; y++) {
let offset = y * width;
@@ -255,6 +257,6 @@ impl GlobalHistogramBinarizer {
x -= 1;
}
Ok((bestValley as u32) << GlobalHistogramBinarizer::LUMINANCE_SHIFT)
Ok((bestValley as u32) << LUMINANCE_SHIFT)
}
}

View File

@@ -20,7 +20,7 @@
// import com.google.zxing.LuminanceSource;
// import com.google.zxing.NotFoundException;
use std::{borrow::Cow, rc::Rc};
use std::borrow::Cow;
use once_cell::unsync::OnceCell;
@@ -46,20 +46,22 @@ use super::{BitArray, BitMatrix, GlobalHistogramBinarizer};
*
* @author dswitkin@google.com (Daniel Switkin)
*/
pub struct HybridBinarizer {
pub struct HybridBinarizer<LS: LuminanceSource> {
//width: usize,
//height: usize,
//source: Box<dyn LuminanceSource>,
ghb: GlobalHistogramBinarizer,
ghb: GlobalHistogramBinarizer<LS>,
black_matrix: OnceCell<BitMatrix>,
}
impl Binarizer for HybridBinarizer {
fn getLuminanceSource(&self) -> &Box<dyn LuminanceSource> {
self.ghb.getLuminanceSource()
impl<LS: LuminanceSource> Binarizer for HybridBinarizer<LS> {
type Source = LS;
fn get_luminance_source(&self) -> &LS {
self.ghb.get_luminance_source()
}
fn getBlackRow(&self, y: usize) -> Result<Cow<BitArray>> {
self.ghb.getBlackRow(y)
fn get_black_row(&self, y: usize) -> Result<Cow<BitArray>> {
self.ghb.get_black_row(y)
}
/**
@@ -67,35 +69,36 @@ impl Binarizer for HybridBinarizer {
* constructor instead, but there are some advantages to doing it lazily, such as making
* profiling easier, and not doing heavy lifting when callers don't expect it.
*/
fn getBlackMatrix(&self) -> Result<&BitMatrix> {
fn get_black_matrix(&self) -> Result<&BitMatrix> {
let matrix = self
.black_matrix
.get_or_try_init(|| Self::calculateBlackMatrix(&self.ghb))?;
Ok(matrix)
}
fn createBinarizer(&self, source: Box<dyn LuminanceSource>) -> Rc<dyn Binarizer> {
Rc::new(HybridBinarizer::new(source))
fn create_binarizer(&self, source: LS) -> Self {
Self::new(source)
}
fn getWidth(&self) -> usize {
self.ghb.getWidth()
fn get_width(&self) -> usize {
self.ghb.get_width()
}
fn getHeight(&self) -> usize {
self.ghb.getHeight()
fn get_height(&self) -> usize {
self.ghb.get_height()
}
}
impl HybridBinarizer {
// This class uses 5x5 blocks to compute local luminance, where each block is 8x8 pixels.
// So this is the smallest dimension in each axis we can accept.
const BLOCK_SIZE_POWER: usize = 3;
const BLOCK_SIZE: usize = 1 << HybridBinarizer::BLOCK_SIZE_POWER; // ...0100...00
const BLOCK_SIZE_MASK: usize = HybridBinarizer::BLOCK_SIZE - 1; // ...0011...11
const MINIMUM_DIMENSION: usize = HybridBinarizer::BLOCK_SIZE * 5;
const MIN_DYNAMIC_RANGE: usize = 24;
pub fn new(source: Box<dyn LuminanceSource>) -> Self {
// This class uses 5x5 blocks to compute local luminance, where each block is 8x8 pixels.
// So this is the smallest dimension in each axis we can accept.
const BLOCK_SIZE_POWER: usize = 3;
const BLOCK_SIZE: usize = 1 << BLOCK_SIZE_POWER; // ...0100...00
const BLOCK_SIZE_MASK: usize = BLOCK_SIZE - 1; // ...0011...11
const MINIMUM_DIMENSION: usize = BLOCK_SIZE * 5;
const MIN_DYNAMIC_RANGE: usize = 24;
impl<LS: LuminanceSource> HybridBinarizer<LS> {
pub fn new(source: LS) -> Self {
let ghb = GlobalHistogramBinarizer::new(source);
Self {
black_matrix: OnceCell::new(),
@@ -103,21 +106,21 @@ impl HybridBinarizer {
}
}
fn calculateBlackMatrix(ghb: &GlobalHistogramBinarizer) -> Result<BitMatrix> {
fn calculateBlackMatrix<LS2: LuminanceSource>(
ghb: &GlobalHistogramBinarizer<LS2>,
) -> Result<BitMatrix> {
// let matrix;
let source = ghb.getLuminanceSource();
let width = source.getWidth();
let height = source.getHeight();
let matrix = if width >= HybridBinarizer::MINIMUM_DIMENSION
&& height >= HybridBinarizer::MINIMUM_DIMENSION
{
let luminances = source.getMatrix();
let mut sub_width = width >> HybridBinarizer::BLOCK_SIZE_POWER;
if (width & HybridBinarizer::BLOCK_SIZE_MASK) != 0 {
let source = ghb.get_luminance_source();
let width = source.get_width();
let height = source.get_height();
let matrix = if width >= MINIMUM_DIMENSION && height >= MINIMUM_DIMENSION {
let luminances = source.get_matrix();
let mut sub_width = width >> BLOCK_SIZE_POWER;
if (width & BLOCK_SIZE_MASK) != 0 {
sub_width += 1;
}
let mut sub_height = height >> HybridBinarizer::BLOCK_SIZE_POWER;
if (height & HybridBinarizer::BLOCK_SIZE_MASK) != 0 {
let mut sub_height = height >> BLOCK_SIZE_POWER;
if (height & BLOCK_SIZE_MASK) != 0 {
sub_height += 1;
}
let black_points = Self::calculateBlackPoints(
@@ -141,7 +144,7 @@ impl HybridBinarizer {
Ok(new_matrix)
} else {
// If the image is too small, fall back to the global histogram approach.
let m = ghb.getBlackMatrix()?;
let m = ghb.get_black_matrix()?;
Ok(m.clone())
};
// dbg!(matrix.to_string());
@@ -162,18 +165,18 @@ impl HybridBinarizer {
black_points: &[Vec<u32>],
matrix: &mut BitMatrix,
) {
let maxYOffset = height - HybridBinarizer::BLOCK_SIZE as u32;
let maxXOffset = width - HybridBinarizer::BLOCK_SIZE as u32;
let maxYOffset = height - BLOCK_SIZE as u32;
let maxXOffset = width - BLOCK_SIZE as u32;
for y in 0..sub_height {
// for (int y = 0; y < subHeight; y++) {
let mut yoffset = y << HybridBinarizer::BLOCK_SIZE_POWER;
let mut yoffset = y << BLOCK_SIZE_POWER;
if yoffset > maxYOffset {
yoffset = maxYOffset;
}
let top = Self::cap(y, sub_height - 3);
for x in 0..sub_width {
// for (int x = 0; x < subWidth; x++) {
let mut xoffset = x << HybridBinarizer::BLOCK_SIZE_POWER;
let mut xoffset = x << BLOCK_SIZE_POWER;
if xoffset > maxXOffset {
xoffset = maxXOffset;
}
@@ -215,9 +218,9 @@ impl HybridBinarizer {
matrix: &mut BitMatrix,
) {
let mut offset = yoffset * stride + xoffset;
for y in 0..HybridBinarizer::BLOCK_SIZE {
for y in 0..BLOCK_SIZE {
// for (int y = 0, offset = yoffset * stride + xoffset; y < HybridBinarizer::BLOCK_SIZE; y++, offset += stride) {
for x in 0..HybridBinarizer::BLOCK_SIZE {
for x in 0..BLOCK_SIZE {
// for (int x = 0; x < HybridBinarizer::BLOCK_SIZE; x++) {
// Comparison needs to be <= so that black == 0 pixels are black even if the threshold is 0.
if luminances[offset as usize + x] as u32 <= threshold {
@@ -240,18 +243,18 @@ impl HybridBinarizer {
width: u32,
height: u32,
) -> Vec<Vec<u32>> {
let maxYOffset = height as usize - HybridBinarizer::BLOCK_SIZE;
let maxXOffset = width as usize - HybridBinarizer::BLOCK_SIZE;
let maxYOffset = height as usize - BLOCK_SIZE;
let maxXOffset = width as usize - BLOCK_SIZE;
let mut blackPoints = vec![vec![0; subWidth as usize]; subHeight as usize];
for y in 0..subHeight {
// for (int y = 0; y < subHeight; y++) {
let mut yoffset = y << HybridBinarizer::BLOCK_SIZE_POWER;
let mut yoffset = y << BLOCK_SIZE_POWER;
if yoffset > maxYOffset as u32 {
yoffset = maxYOffset as u32;
}
for x in 0..subWidth {
// for (int x = 0; x < subWidth; x++) {
let mut xoffset = x << HybridBinarizer::BLOCK_SIZE_POWER;
let mut xoffset = x << BLOCK_SIZE_POWER;
if xoffset > maxXOffset as u32 {
xoffset = maxXOffset as u32;
}
@@ -261,9 +264,9 @@ impl HybridBinarizer {
let mut offset = yoffset * width + xoffset;
let mut yy = 0;
while yy < HybridBinarizer::BLOCK_SIZE {
while yy < BLOCK_SIZE {
// for (int yy = 0, offset = yoffset * width + xoffset; yy < HybridBinarizer::BLOCK_SIZE; yy++, offset += width) {
for xx in 0..HybridBinarizer::BLOCK_SIZE {
for xx in 0..BLOCK_SIZE {
// for (int xx = 0; xx < HybridBinarizer::BLOCK_SIZE; xx++) {
let pixel = luminances[offset as usize + xx];
sum += pixel as u32;
@@ -276,13 +279,13 @@ impl HybridBinarizer {
}
}
// short-circuit min/max tests once dynamic range is met
if (max - min) as usize > HybridBinarizer::MIN_DYNAMIC_RANGE {
if (max - min) as usize > MIN_DYNAMIC_RANGE {
// finish the rest of the rows quickly
offset += width;
yy += 1;
while yy < HybridBinarizer::BLOCK_SIZE {
while yy < BLOCK_SIZE {
// for (yy++, offset += width; yy < HybridBinarizer::BLOCK_SIZE; yy++, offset += width) {
for xx in 0..HybridBinarizer::BLOCK_SIZE {
for xx in 0..BLOCK_SIZE {
// for (int xx = 0; xx < BLOCK_SIZE; xx++) {
sum += luminances[offset as usize + xx] as u32;
}
@@ -296,8 +299,8 @@ impl HybridBinarizer {
}
// The default estimate is the average of the values in the block.
let mut average = sum >> (HybridBinarizer::BLOCK_SIZE_POWER * 2);
if (max - min) as usize <= HybridBinarizer::MIN_DYNAMIC_RANGE {
let mut average = sum >> (BLOCK_SIZE_POWER * 2);
if (max - min) as usize <= MIN_DYNAMIC_RANGE {
// If variation within the block is low, assume this is a block with only light or only
// dark pixels. In that case we do not want to use the average, as it would divide this
// low contrast area into black and white pixels, essentially creating data out of noise.

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -17,7 +17,7 @@
use std::collections::HashMap;
use crate::common::Result;
use crate::{point, Exceptions, Point, RXingResult, Reader};
use crate::{point, Binarizer, Exceptions, Point, RXingResult, Reader};
/**
* This class attempts to decode a barcode from an image, not by scanning the whole image,
@@ -30,17 +30,17 @@ use crate::{point, Exceptions, Point, RXingResult, Reader};
*/
pub struct ByQuadrantReader<T: Reader>(T);
impl<T: Reader> Reader for ByQuadrantReader<T> {
fn decode(&mut self, image: &mut crate::BinaryBitmap) -> Result<crate::RXingResult> {
fn decode<B: Binarizer>(&mut self, image: &mut crate::BinaryBitmap<B>) -> Result<RXingResult> {
self.decode_with_hints(image, &HashMap::new())
}
fn decode_with_hints(
fn decode_with_hints<B: Binarizer>(
&mut self,
image: &mut crate::BinaryBitmap,
image: &mut crate::BinaryBitmap<B>,
hints: &crate::DecodingHintDictionary,
) -> Result<crate::RXingResult> {
let width = image.getWidth();
let height = image.getHeight();
let width = image.get_width();
let height = image.get_height();
let halfWidth = width / 2;
let halfHeight = height / 2;

View File

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

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
use crate::{common::Result, BinaryBitmap, DecodingHintDictionary, RXingResult};
use crate::{common::Result, Binarizer, BinaryBitmap, DecodingHintDictionary, RXingResult};
/**
* Implementation of this interface attempt to read several barcodes from one image.
@@ -23,11 +23,14 @@ use crate::{common::Result, BinaryBitmap, DecodingHintDictionary, RXingResult};
* @author Sean Owen
*/
pub trait MultipleBarcodeReader {
fn decode_multiple(&mut self, image: &mut BinaryBitmap) -> Result<Vec<RXingResult>>;
fn decode_multiple_with_hints(
fn decode_multiple<B: Binarizer>(
&mut self,
image: &mut BinaryBitmap,
image: &mut BinaryBitmap<B>,
) -> Result<Vec<RXingResult>>;
fn decode_multiple_with_hints<B: Binarizer>(
&mut self,
image: &mut BinaryBitmap<B>,
hints: &DecodingHintDictionary,
) -> Result<Vec<RXingResult>>;
}

View File

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

View File

@@ -14,14 +14,14 @@
* limitations under the License.
*/
use std::collections::HashMap;
use std::collections::{HashMap, HashSet};
use crate::common::Result;
use crate::{
aztec::AztecReader, datamatrix::DataMatrixReader, maxicode::MaxiCodeReader,
oned::MultiFormatOneDReader, pdf417::PDF417Reader, qrcode::QRCodeReader, BarcodeFormat,
BinaryBitmap, DecodeHintType, DecodeHintValue, DecodingHintDictionary, Exceptions, RXingResult,
Reader,
Binarizer, BinaryBitmap, DecodeHintType, DecodeHintValue, DecodingHintDictionary, Exceptions,
RXingResult, Reader,
};
/**
@@ -35,7 +35,8 @@ use crate::{
#[derive(Default)]
pub struct MultiFormatReader {
hints: DecodingHintDictionary,
readers: Vec<Box<dyn Reader>>,
possible_formats: HashSet<BarcodeFormat>,
try_harder: bool,
}
impl Reader for MultiFormatReader {
@@ -48,8 +49,8 @@ impl Reader for MultiFormatReader {
* @return The contents of the image
* @throws NotFoundException Any errors which occurred
*/
fn decode(&mut self, image: &mut crate::BinaryBitmap) -> Result<crate::RXingResult> {
self.set_ints(&HashMap::new());
fn decode<B: Binarizer>(&mut self, image: &mut BinaryBitmap<B>) -> Result<RXingResult> {
self.set_hints(&HashMap::new());
self.decode_internal(image)
}
@@ -61,20 +62,14 @@ impl Reader for MultiFormatReader {
* @return The contents of the image
* @throws NotFoundException Any errors which occurred
*/
fn decode_with_hints(
fn decode_with_hints<B: Binarizer>(
&mut self,
image: &mut crate::BinaryBitmap,
hints: &crate::DecodingHintDictionary,
) -> Result<crate::RXingResult> {
self.set_ints(hints);
image: &mut BinaryBitmap<B>,
hints: &DecodingHintDictionary,
) -> Result<RXingResult> {
self.set_hints(hints);
self.decode_internal(image)
}
fn reset(&mut self) {
for reader in self.readers.iter_mut() {
reader.reset();
}
}
}
impl MultiFormatReader {
@@ -86,10 +81,13 @@ impl MultiFormatReader {
* @return The contents of the image
* @throws NotFoundException Any errors which occurred
*/
pub fn decode_with_state(&mut self, image: &mut BinaryBitmap) -> Result<RXingResult> {
pub fn decode_with_state<B: Binarizer>(
&mut self,
image: &mut BinaryBitmap<B>,
) -> Result<RXingResult> {
// Make sure to set up the default state so we don't crash
if self.readers.is_empty() {
self.set_ints(&HashMap::new());
if self.possible_formats.is_empty() {
self.set_hints(&HashMap::new());
}
self.decode_internal(image)
}
@@ -101,92 +99,130 @@ impl MultiFormatReader {
*
* @param hints The set of hints to use for subsequent calls to decode(image)
*/
pub fn set_ints(&mut self, hints: &DecodingHintDictionary) {
pub fn set_hints(&mut self, hints: &DecodingHintDictionary) {
self.hints = hints.clone();
let tryHarder = matches!(
self.try_harder = matches!(
self.hints.get(&DecodeHintType::TRY_HARDER),
Some(DecodeHintValue::TryHarder(true))
);
let formats = hints.get(&DecodeHintType::POSSIBLE_FORMATS);
let mut readers: Vec<Box<dyn Reader>> = Vec::new();
if let Some(DecodeHintValue::PossibleFormats(formats)) = formats {
let addOneDReader = formats.contains(&BarcodeFormat::UPC_A)
|| formats.contains(&BarcodeFormat::UPC_E)
|| formats.contains(&BarcodeFormat::EAN_13)
|| formats.contains(&BarcodeFormat::EAN_8)
|| formats.contains(&BarcodeFormat::CODABAR)
|| formats.contains(&BarcodeFormat::CODE_39)
|| formats.contains(&BarcodeFormat::CODE_93)
|| formats.contains(&BarcodeFormat::CODE_128)
|| formats.contains(&BarcodeFormat::ITF)
|| formats.contains(&BarcodeFormat::RSS_14)
|| formats.contains(&BarcodeFormat::RSS_EXPANDED);
// Put 1D readers upfront in "normal" mode
if addOneDReader && !tryHarder {
readers.push(Box::new(MultiFormatOneDReader::new(hints)));
}
if formats.contains(&BarcodeFormat::QR_CODE) {
readers.push(Box::<QRCodeReader>::default());
}
if formats.contains(&BarcodeFormat::DATA_MATRIX) {
readers.push(Box::<DataMatrixReader>::default());
}
if formats.contains(&BarcodeFormat::AZTEC) {
readers.push(Box::<AztecReader>::default());
}
if formats.contains(&BarcodeFormat::PDF_417) {
readers.push(Box::<PDF417Reader>::default());
}
if formats.contains(&BarcodeFormat::MAXICODE) {
readers.push(Box::<MaxiCodeReader>::default());
}
// At end in "try harder" mode
if addOneDReader && tryHarder {
readers.push(Box::new(MultiFormatOneDReader::new(hints)));
}
}
if readers.is_empty() {
if !tryHarder {
readers.push(Box::new(MultiFormatOneDReader::new(hints)));
}
readers.push(Box::<QRCodeReader>::default());
readers.push(Box::<DataMatrixReader>::default());
readers.push(Box::<AztecReader>::default());
readers.push(Box::<PDF417Reader>::default());
readers.push(Box::<MaxiCodeReader>::default());
if tryHarder {
readers.push(Box::new(MultiFormatOneDReader::new(hints)));
}
}
self.readers = readers;
self.possible_formats = if let Some(DecodeHintValue::PossibleFormats(formats)) =
hints.get(&DecodeHintType::POSSIBLE_FORMATS)
{
formats.clone()
} else {
HashSet::new()
};
}
pub fn decode_internal(&mut self, image: &mut BinaryBitmap) -> Result<RXingResult> {
if !self.readers.is_empty() {
for reader in self.readers.iter_mut() {
let res = reader.decode_with_hints(image, &self.hints);
if res.is_ok() {
return res;
}
pub fn decode_internal<B: Binarizer>(
&mut self,
image: &mut BinaryBitmap<B>,
) -> Result<RXingResult> {
if !self.possible_formats.is_empty() {
let res = self.decode_formats(image);
if res.is_ok() {
return res;
}
if matches!(
self.hints.get(&DecodeHintType::ALSO_INVERTED),
Some(DecodeHintValue::AlsoInverted(true))
) {
// Calling all readers again with inverted image
image.getBlackMatrixMut().flip_self();
for reader in self.readers.iter_mut() {
let res = reader.decode_with_hints(image, &self.hints);
if res.is_ok() {
return res;
}
image.get_black_matrix_mut().flip_self();
let res = self.decode_formats(image);
if res.is_ok() {
return res;
}
}
}
Err(Exceptions::NOT_FOUND)
}
fn decode_formats<B: Binarizer>(&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 {
fn decodeRow(
fn decode_row(
&mut self,
rowNumber: u32,
row: &crate::common::BitArray,
@@ -309,7 +309,7 @@ impl CodaBarReader {
self.counterLength = 0;
// Start from the first white bit.
let mut i = row.getNextUnset(0);
let end = row.getSize();
let end = row.get_size();
if i >= end {
return Err(Exceptions::NOT_FOUND);
}

View File

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -24,25 +24,110 @@ use super::ITFReader;
use super::MultiFormatUPCEANReader;
use super::OneDReader;
use crate::common::Result;
use crate::BarcodeFormat;
use crate::DecodeHintValue;
use crate::Exceptions;
use crate::{BarcodeFormat, Binarizer, RXingResult};
/**
* @author dswitkin@google.com (Daniel Switkin)
* @author Sean Owen
*/
#[derive(Default)]
pub struct MultiFormatOneDReader(Vec<Box<dyn OneDReader>>);
pub struct MultiFormatOneDReader {
internal_hints: DecodingHintDictionary,
possible_formats: HashSet<BarcodeFormat>,
use_code_39_check_digit: bool,
}
impl OneDReader for MultiFormatOneDReader {
fn decodeRow(
fn decode_row(
&mut self,
rowNumber: u32,
row_number: u32,
row: &crate::common::BitArray,
hints: &crate::DecodingHintDictionary,
) -> Result<crate::RXingResult> {
for reader in self.0.iter_mut() {
if let Ok(res) = reader.decodeRow(rowNumber, row, hints) {
hints: &DecodingHintDictionary,
) -> Result<RXingResult> {
// reader.decode_row(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);
}
}
@@ -52,57 +137,23 @@ impl OneDReader for MultiFormatOneDReader {
}
impl MultiFormatOneDReader {
pub fn new(hints: &DecodingHintDictionary) -> Self {
let useCode39CheckDigit = matches!(
let use_code_39_check_digit = matches!(
hints.get(&DecodeHintType::ASSUME_CODE_39_CHECK_DIGIT),
Some(DecodeHintValue::AssumeCode39CheckDigit(true))
);
let mut readers: Vec<Box<dyn OneDReader>> = Vec::new();
if let Some(DecodeHintValue::PossibleFormats(possibleFormats)) =
let possible_formats = if let Some(DecodeHintValue::PossibleFormats(p)) =
hints.get(&DecodeHintType::POSSIBLE_FORMATS)
{
if possibleFormats.contains(&BarcodeFormat::EAN_13)
|| possibleFormats.contains(&BarcodeFormat::UPC_A)
|| possibleFormats.contains(&BarcodeFormat::EAN_8)
|| possibleFormats.contains(&BarcodeFormat::UPC_E)
{
readers.push(Box::new(MultiFormatUPCEANReader::new(hints)));
}
if possibleFormats.contains(&BarcodeFormat::CODE_39) {
readers.push(Box::new(Code39Reader::with_use_check_digit(
useCode39CheckDigit,
)));
}
if possibleFormats.contains(&BarcodeFormat::CODE_93) {
readers.push(Box::<Code93Reader>::default());
}
if possibleFormats.contains(&BarcodeFormat::CODE_128) {
readers.push(Box::<Code128Reader>::default());
}
if possibleFormats.contains(&BarcodeFormat::ITF) {
readers.push(Box::<ITFReader>::default());
}
if possibleFormats.contains(&BarcodeFormat::CODABAR) {
readers.push(Box::<CodaBarReader>::default());
}
if possibleFormats.contains(&BarcodeFormat::RSS_14) {
readers.push(Box::<RSS14Reader>::default());
}
if possibleFormats.contains(&BarcodeFormat::RSS_EXPANDED) {
readers.push(Box::<RSSExpandedReader>::default());
}
}
if readers.is_empty() {
readers.push(Box::new(MultiFormatUPCEANReader::new(hints)));
readers.push(Box::<Code39Reader>::default());
readers.push(Box::<CodaBarReader>::default());
readers.push(Box::<Code93Reader>::default());
readers.push(Box::<Code128Reader>::default());
readers.push(Box::<ITFReader>::default());
readers.push(Box::<RSS14Reader>::default());
readers.push(Box::<RSSExpandedReader>::default());
}
p.clone()
} else {
HashSet::new()
};
Self(readers)
Self {
possible_formats,
use_code_39_check_digit,
internal_hints: hints.clone(),
}
}
}
@@ -111,20 +162,20 @@ use crate::DecodingHintDictionary;
use crate::RXingResultMetadataType;
use crate::RXingResultMetadataValue;
use crate::Reader;
use std::collections::HashMap;
use std::collections::{HashMap, HashSet};
impl Reader for MultiFormatOneDReader {
fn decode(&mut self, image: &mut crate::BinaryBitmap) -> Result<crate::RXingResult> {
fn decode<B: Binarizer>(&mut self, image: &mut crate::BinaryBitmap<B>) -> Result<RXingResult> {
self.decode_with_hints(image, &HashMap::new())
}
// Note that we don't try rotation without the try harder flag, even if rotation was supported.
fn decode_with_hints(
fn decode_with_hints<B: Binarizer>(
&mut self,
image: &mut crate::BinaryBitmap,
image: &mut crate::BinaryBitmap<B>,
hints: &DecodingHintDictionary,
) -> Result<crate::RXingResult> {
let first_try = self.doDecode(image, hints);
) -> Result<RXingResult> {
let first_try = self._do_decode(image, hints);
if first_try.is_ok() {
return first_try;
}
@@ -133,9 +184,9 @@ impl Reader for MultiFormatOneDReader {
hints.get(&DecodeHintType::TRY_HARDER),
Some(DecodeHintValue::TryHarder(true))
);
if tryHarder && image.isRotateSupported() {
let mut rotatedImage = image.rotateCounterClockwise();
let mut result = self.doDecode(&mut rotatedImage, hints)?;
if tryHarder && image.is_rotate_supported() {
let mut rotatedImage = image.rotate_counter_clockwise();
let mut result = self._do_decode(&mut rotatedImage, hints)?;
// Record that we found it rotated 90 degrees CCW / 270 degrees CW
let metadata = result.getRXingResultMetadata();
let mut orientation = 270;
@@ -156,7 +207,7 @@ impl Reader for MultiFormatOneDReader {
RXingResultMetadataValue::Orientation(orientation),
);
// Update result points
let height = rotatedImage.getHeight();
let height = rotatedImage.get_height();
let total_points = result.getPoints().len();
let points = result.getPointsMut();
for point in points.iter_mut().take(total_points) {
@@ -169,10 +220,4 @@ impl Reader for MultiFormatOneDReader {
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::BarcodeFormat;
use crate::DecodeHintValue;
use crate::Exceptions;
use crate::RXingResult;
use crate::Reader;
use crate::{BarcodeFormat, Binarizer};
use super::EAN13Reader;
use super::EAN8Reader;
@@ -35,47 +35,122 @@ use super::{OneDReader, UPCEANReader};
*
* @author Sean Owen
*/
pub struct MultiFormatUPCEANReader(Vec<Box<dyn UPCEANReader>>);
pub struct MultiFormatUPCEANReader {
possible_formats: HashSet<BarcodeFormat>,
}
impl OneDReader for MultiFormatUPCEANReader {
fn decode_row(
&mut self,
rowNumber: u32,
row: &crate::common::BitArray,
hints: &DecodingHintDictionary,
) -> Result<RXingResult> {
let Self {
ref possible_formats,
} = self;
// Compute this location once and reuse it on multiple implementations
let start_guard_pattern = STAND_IN.find_start_guard_pattern(row)?;
if !possible_formats.is_empty() {
if possible_formats.contains(&BarcodeFormat::EAN_13) {
if let Ok(res) = self.try_decode_function(
&EAN13Reader::default(),
rowNumber,
row,
hints,
&start_guard_pattern,
) {
return Ok(res);
}
} else if possible_formats.contains(&BarcodeFormat::UPC_A) {
if let Ok(res) = self.try_decode_function(
&UPCAReader::default(),
rowNumber,
row,
hints,
&start_guard_pattern,
) {
return Ok(res);
}
}
if possible_formats.contains(&BarcodeFormat::EAN_8) {
if let Ok(res) = self.try_decode_function(
&EAN8Reader::default(),
rowNumber,
row,
hints,
&start_guard_pattern,
) {
return Ok(res);
}
}
if possible_formats.contains(&BarcodeFormat::UPC_E) {
if let Ok(res) = self.try_decode_function(
&UPCEReader::default(),
rowNumber,
row,
hints,
&start_guard_pattern,
) {
return Ok(res);
}
}
} else {
if let Ok(res) = self.try_decode_function(
&EAN13Reader::default(),
rowNumber,
row,
hints,
&start_guard_pattern,
) {
return Ok(res);
}
if let Ok(res) = self.try_decode_function(
&EAN8Reader::default(),
rowNumber,
row,
hints,
&start_guard_pattern,
) {
return Ok(res);
}
if let Ok(res) = self.try_decode_function(
&UPCEReader::default(),
rowNumber,
row,
hints,
&start_guard_pattern,
) {
return Ok(res);
}
}
Err(Exceptions::NOT_FOUND)
}
}
impl MultiFormatUPCEANReader {
pub fn new(hints: &DecodingHintDictionary) -> Self {
let mut readers: Vec<Box<dyn UPCEANReader>> = Vec::new();
if let Some(DecodeHintValue::PossibleFormats(possibleFormats)) =
let possible_formats = if let Some(DecodeHintValue::PossibleFormats(p)) =
hints.get(&DecodeHintType::POSSIBLE_FORMATS)
{
// Collection<BarcodeFormat> possibleFormats = hints == null ? null :
// (Collection<BarcodeFormat>) hints.get(DecodeHintType.POSSIBLE_FORMATS);
// Collection<UPCEANReader> readers = new ArrayList<>();
if possibleFormats.contains(&BarcodeFormat::EAN_13) {
readers.push(Box::<EAN13Reader>::default());
} else if possibleFormats.contains(&BarcodeFormat::UPC_A) {
readers.push(Box::<UPCAReader>::default());
}
if possibleFormats.contains(&BarcodeFormat::EAN_8) {
readers.push(Box::<EAN8Reader>::default());
}
if possibleFormats.contains(&BarcodeFormat::UPC_E) {
readers.push(Box::<UPCEReader>::default());
}
}
if readers.is_empty() {
readers.push(Box::<EAN13Reader>::default());
// UPC-A is covered by EAN-13
readers.push(Box::<EAN8Reader>::default());
readers.push(Box::<UPCEReader>::default());
}
p.clone()
} else {
HashSet::default()
};
Self(readers)
Self { possible_formats }
}
fn try_decode_function(
fn try_decode_function<R: UPCEANReader>(
&self,
reader: &Box<dyn UPCEANReader>,
reader: &R,
rowNumber: u32,
row: &crate::common::BitArray,
hints: &crate::DecodingHintDictionary,
hints: &DecodingHintDictionary,
startGuardPattern: &[usize; 2],
) -> Result<crate::RXingResult> {
) -> Result<RXingResult> {
let result = reader.decodeRowWithGuardRange(rowNumber, row, startGuardPattern, hints)?;
// Special case: a 12-digit code encoded in UPC-A is identical to a "0"
// followed by those 12 digits encoded as EAN-13. Each will recognize such a code,
@@ -117,46 +192,24 @@ impl MultiFormatUPCEANReader {
}
}
impl OneDReader for MultiFormatUPCEANReader {
fn decodeRow(
&mut self,
rowNumber: u32,
row: &crate::common::BitArray,
hints: &crate::DecodingHintDictionary,
) -> Result<crate::RXingResult> {
// Compute this location once and reuse it on multiple implementations
let startGuardPattern = STAND_IN.findStartGuardPattern(row)?;
for reader in &self.0 {
// for (UPCEANReader reader : readers) {
let try_result =
self.try_decode_function(reader, rowNumber, row, hints, &startGuardPattern);
if try_result.is_ok() {
return try_result;
}
}
Err(Exceptions::NOT_FOUND)
}
}
use crate::DecodeHintType;
use crate::DecodingHintDictionary;
use crate::RXingResultMetadataType;
use crate::RXingResultMetadataValue;
use std::collections::HashMap;
use std::collections::{HashMap, HashSet};
impl Reader for MultiFormatUPCEANReader {
fn decode(&mut self, image: &mut crate::BinaryBitmap) -> Result<crate::RXingResult> {
fn decode<B: Binarizer>(&mut self, image: &mut crate::BinaryBitmap<B>) -> Result<RXingResult> {
self.decode_with_hints(image, &HashMap::new())
}
// Note that we don't try rotation without the try harder flag, even if rotation was supported.
fn decode_with_hints(
fn decode_with_hints<B: Binarizer>(
&mut self,
image: &mut crate::BinaryBitmap,
image: &mut crate::BinaryBitmap<B>,
hints: &DecodingHintDictionary,
) -> Result<crate::RXingResult> {
let first_try = self.doDecode(image, hints);
) -> Result<RXingResult> {
let first_try = self._do_decode(image, hints);
if first_try.is_ok() {
return first_try;
}
@@ -165,16 +218,16 @@ impl Reader for MultiFormatUPCEANReader {
hints.get(&DecodeHintType::TRY_HARDER),
Some(DecodeHintValue::TryHarder(true))
);
if tryHarder && image.isRotateSupported() {
let mut rotatedImage = image.rotateCounterClockwise();
let mut result = self.doDecode(&mut rotatedImage, hints)?;
if tryHarder && image.is_rotate_supported() {
let mut rotatedImage = image.rotate_counter_clockwise();
let mut result = self._do_decode(&mut rotatedImage, hints)?;
// Record that we found it rotated 90 degrees CCW / 270 degrees CW
let metadata = result.getRXingResultMetadata();
let mut orientation = 270;
if metadata.contains_key(&RXingResultMetadataType::ORIENTATION) {
// But if we found it reversed in doDecode(), add in that result here:
orientation = (orientation
+ if let Some(crate::RXingResultMetadataValue::Orientation(or)) =
+ if let Some(RXingResultMetadataValue::Orientation(or)) =
metadata.get(&RXingResultMetadataType::ORIENTATION)
{
*or
@@ -188,7 +241,7 @@ impl Reader for MultiFormatUPCEANReader {
RXingResultMetadataValue::Orientation(orientation),
);
// Update result points
let height = rotatedImage.getHeight();
let height = rotatedImage.get_height();
let total_points = result.getPoints().len();
let points = result.getPointsMut();
for point in points.iter_mut().take(total_points) {
@@ -201,10 +254,4 @@ impl Reader for MultiFormatUPCEANReader {
Err(Exceptions::NOT_FOUND)
}
}
fn reset(&mut self) {
for reader in self.0.iter_mut() {
reader.reset();
}
}
}

View File

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

View File

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

View File

@@ -38,7 +38,7 @@ pub struct AI01392xDecoder<'a> {
impl AI01decoder for AI01392xDecoder<'_> {}
impl AbstractExpandedDecoder for AI01392xDecoder<'_> {
fn parseInformation(&mut self) -> Result<String> {
if self.information.getSize() < Self::HEADER_SIZE + Self::GTIN_SIZE as usize {
if self.information.get_size() < Self::HEADER_SIZE + Self::GTIN_SIZE as usize {
return Err(crate::Exceptions::NOT_FOUND);
}

View File

@@ -38,7 +38,7 @@ pub struct AI01393xDecoder<'a> {
impl AI01decoder for AI01393xDecoder<'_> {}
impl AbstractExpandedDecoder for AI01393xDecoder<'_> {
fn parseInformation(&mut self) -> Result<String> {
if self.information.getSize() < Self::HEADER_SIZE + Self::GTIN_SIZE as usize {
if self.information.get_size() < Self::HEADER_SIZE + Self::GTIN_SIZE as usize {
return Err(crate::Exceptions::NOT_FOUND);
}

View File

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

View File

@@ -50,7 +50,7 @@ impl AI01weightDecoder for AI013x0xDecoder<'_> {
}
impl AbstractExpandedDecoder for AI013x0xDecoder<'_> {
fn parseInformation(&mut self) -> Result<String> {
if self.information.getSize()
if self.information.get_size()
!= Self::HEADER_SIZE + Self::GTIN_SIZE as usize + Self::WEIGHT_SIZE
{
return Err(crate::Exceptions::NOT_FOUND);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -286,7 +286,7 @@ fn calculateBitsNeeded(
data_bits: &BitArray,
version: VersionRef,
) -> u32 {
(header_bits.getSize() + mode.getCharacterCountBits(version) as usize + data_bits.getSize())
(header_bits.get_size() + mode.getCharacterCountBits(version) as usize + data_bits.get_size())
as u32
}
@@ -413,21 +413,21 @@ pub fn willFit(numInputBits: u32, version: VersionRef, ecLevel: &ErrorCorrection
*/
pub fn terminateBits(num_data_bytes: u32, bits: &mut BitArray) -> Result<()> {
let capacity = num_data_bytes * 8;
if bits.getSize() > capacity as usize {
if bits.get_size() > capacity as usize {
return Err(Exceptions::writer_with(format!(
"data bits cannot fit in the QR Code{capacity} > "
)));
}
// Append Mode.TERMINATE if there is enough space (value is 0000)
for _i in 0..4 {
if bits.getSize() >= capacity as usize {
if bits.get_size() >= capacity as usize {
break;
}
bits.appendBit(false);
}
// Append termination bits. See 8.4.8 of JISX0510:2004 (p.24) for details.
// If the last byte isn't 8-bit aligned, we'll add padding bits.
let num_bits_in_last_byte = bits.getSize() & 0x07;
let num_bits_in_last_byte = bits.get_size() & 0x07;
if num_bits_in_last_byte > 0 {
for _i in num_bits_in_last_byte..8 {
bits.appendBit(false);
@@ -441,7 +441,7 @@ pub fn terminateBits(num_data_bytes: u32, bits: &mut BitArray) -> Result<()> {
}
bits.appendBits(if (i & 0x01) == 0 { 0xEC } else { 0x11 }, 8)?;
}
if bits.getSize() != capacity as usize {
if bits.get_size() != capacity as usize {
return Err(Exceptions::writer_with("Bits size does not equal capacity"));
}
Ok(())

View File

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

View File

@@ -16,7 +16,7 @@
//package com.google.zxing;
use crate::{common::Result, BinaryBitmap, DecodingHintDictionary, RXingResult};
use crate::{common::Result, Binarizer, BinaryBitmap, DecodingHintDictionary, RXingResult};
/**
* Implementations of this interface can decode an image of a barcode in some format into
@@ -40,7 +40,7 @@ pub trait Reader {
* @throws ChecksumException if a potential barcode is found but does not pass its checksum
* @throws FormatException if a potential barcode is found but format is invalid
*/
fn decode(&mut self, image: &mut BinaryBitmap) -> Result<RXingResult>;
fn decode<B: Binarizer>(&mut self, image: &mut BinaryBitmap<B>) -> Result<RXingResult>;
/**
* Locates and decodes a barcode in some format within an image. This method also accepts
@@ -56,9 +56,9 @@ pub trait Reader {
* @throws ChecksumException if a potential barcode is found but does not pass its checksum
* @throws FormatException if a potential barcode is found but format is invalid
*/
fn decode_with_hints(
fn decode_with_hints<B: Binarizer>(
&mut self,
image: &mut BinaryBitmap,
image: &mut BinaryBitmap<B>,
hints: &DecodingHintDictionary,
) -> Result<RXingResult>;

View File

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

View File

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

View File

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