mirror of
https://github.com/starovoid/rxing.git
synced 2026-07-26 04:12:34 +00:00
Initial generics
This commit is contained in:
@@ -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)
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -52,10 +52,10 @@ fn test_no_crop() {
|
||||
false,
|
||||
)
|
||||
.unwrap();
|
||||
assert_equals(&Y, 0, &source.getMatrix(), 0, Y.len());
|
||||
assert_equals(&Y, 0, &source.get_matrix(), 0, Y.len());
|
||||
for r in 0..ROWS {
|
||||
// for (int r = 0; r < ROWS; r++) {
|
||||
assert_equals(&Y, r * COLS, &source.getRow(r), 0, COLS);
|
||||
assert_equals(&Y, r * COLS, &source.get_row(r), 0, COLS);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,8 +73,8 @@ fn test_crop() {
|
||||
false,
|
||||
)
|
||||
.unwrap();
|
||||
assert!(source.isCropSupported());
|
||||
let cropMatrix = source.getMatrix();
|
||||
assert!(source.is_crop_supported());
|
||||
let cropMatrix = source.get_matrix();
|
||||
for r in 0..ROWS - 2 {
|
||||
// for (int r = 0; r < ROWS - 2; r++) {
|
||||
assert_equals(
|
||||
@@ -87,7 +87,7 @@ fn test_crop() {
|
||||
}
|
||||
for r in 0..ROWS - 2 {
|
||||
// for (int r = 0; r < ROWS - 2; r++) {
|
||||
assert_equals(&Y, (r + 1) * COLS + 1, &source.getRow(r), 0, COLS - 2);
|
||||
assert_equals(&Y, (r + 1) * COLS + 1, &source.get_row(r), 0, COLS - 2);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ use std::collections::HashMap;
|
||||
use crate::{
|
||||
common::{DecoderRXingResult, DetectorRXingResult, Result},
|
||||
exceptions::Exceptions,
|
||||
BarcodeFormat, BinaryBitmap, DecodeHintType, DecodeHintValue, RXingResult,
|
||||
BarcodeFormat, Binarizer, BinaryBitmap, DecodeHintType, DecodeHintValue, RXingResult,
|
||||
RXingResultMetadataType, RXingResultMetadataValue, Reader,
|
||||
};
|
||||
|
||||
@@ -41,18 +41,18 @@ impl Reader for AztecReader {
|
||||
* @throws NotFoundException if a Data Matrix code cannot be found
|
||||
* @throws FormatException if a Data Matrix code cannot be decoded
|
||||
*/
|
||||
fn decode(&mut self, image: &mut BinaryBitmap) -> Result<RXingResult> {
|
||||
fn decode<B: Binarizer>(&mut self, image: &mut BinaryBitmap<B>) -> Result<RXingResult> {
|
||||
self.decode_with_hints(image, &HashMap::new())
|
||||
}
|
||||
|
||||
fn decode_with_hints(
|
||||
fn decode_with_hints<B: Binarizer>(
|
||||
&mut self,
|
||||
image: &mut BinaryBitmap,
|
||||
image: &mut BinaryBitmap<B>,
|
||||
hints: &HashMap<DecodeHintType, DecodeHintValue>,
|
||||
) -> Result<RXingResult> {
|
||||
// let notFoundException = None;
|
||||
// let formatException = None;
|
||||
let mut detector = Detector::new(image.getBlackMatrix());
|
||||
let mut detector = Detector::new(image.get_black_matrix());
|
||||
|
||||
// try {
|
||||
|
||||
|
||||
@@ -157,8 +157,8 @@ pub fn encode_bytes_with_charset(
|
||||
let bits = HighLevelEncoder::with_charset(data.into(), charset).encode()?;
|
||||
|
||||
// stuff bits and choose symbol size
|
||||
let ecc_bits = bits.getSize() as u32 * min_eccpercent / 100 + 11;
|
||||
let total_size_bits = bits.getSize() as u32 + ecc_bits;
|
||||
let ecc_bits = bits.get_size() as u32 * min_eccpercent / 100 + 11;
|
||||
let total_size_bits = bits.get_size() as u32 + ecc_bits;
|
||||
let mut compact;
|
||||
let mut layers: u32;
|
||||
let mut total_bits_in_layer_var;
|
||||
@@ -182,12 +182,12 @@ pub fn encode_bytes_with_charset(
|
||||
word_size = WORD_SIZE[layers as usize];
|
||||
let usable_bits_in_layers = total_bits_in_layer_var - (total_bits_in_layer_var % word_size);
|
||||
stuffed_bits = stuffBits(&bits, word_size as usize)?;
|
||||
if stuffed_bits.getSize() as u32 + ecc_bits > usable_bits_in_layers {
|
||||
if stuffed_bits.get_size() as u32 + ecc_bits > usable_bits_in_layers {
|
||||
return Err(Exceptions::illegal_argument_with(
|
||||
"Data to large for user specified layer",
|
||||
));
|
||||
}
|
||||
if compact && stuffed_bits.getSize() as u32 > word_size * 64 {
|
||||
if compact && stuffed_bits.get_size() as u32 > word_size * 64 {
|
||||
// Compact format only allows 64 data words, though C4 can hold more words than that
|
||||
return Err(Exceptions::illegal_argument_with(
|
||||
"Data to large for user specified layer",
|
||||
@@ -216,18 +216,18 @@ pub fn encode_bytes_with_charset(
|
||||
}
|
||||
// [Re]stuff the bits if this is the first opportunity, or if the
|
||||
// wordSize has changed
|
||||
if stuffed_bits.getSize() == 0 || word_size != WORD_SIZE[layers as usize] {
|
||||
if stuffed_bits.get_size() == 0 || word_size != WORD_SIZE[layers as usize] {
|
||||
word_size = WORD_SIZE[layers as usize];
|
||||
stuffed_bits = stuffBits(&bits, word_size as usize)?;
|
||||
}
|
||||
let usable_bits_in_layers =
|
||||
total_bits_in_layer_var - (total_bits_in_layer_var % word_size);
|
||||
if compact && stuffed_bits.getSize() as u32 > word_size * 64 {
|
||||
if compact && stuffed_bits.get_size() as u32 > word_size * 64 {
|
||||
// Compact format only allows 64 data words, though C4 can hold more words than that
|
||||
i += 1;
|
||||
continue;
|
||||
}
|
||||
if stuffed_bits.getSize() as u32 + ecc_bits <= usable_bits_in_layers {
|
||||
if stuffed_bits.get_size() as u32 + ecc_bits <= usable_bits_in_layers {
|
||||
break;
|
||||
}
|
||||
i += 1;
|
||||
@@ -240,7 +240,7 @@ pub fn encode_bytes_with_charset(
|
||||
)?;
|
||||
|
||||
// generate mode message
|
||||
let messageSizeInWords = stuffed_bits.getSize() as u32 / word_size;
|
||||
let messageSizeInWords = stuffed_bits.get_size() as u32 / word_size;
|
||||
let modeMessage = generateModeMessage(compact, layers, messageSizeInWords)?;
|
||||
|
||||
// allocate symbol
|
||||
@@ -429,7 +429,7 @@ fn drawModeMessage(matrix: &mut BitMatrix, compact: bool, matrixSize: u32, modeM
|
||||
|
||||
fn generateCheckWords(bitArray: &BitArray, totalBits: usize, wordSize: usize) -> Result<BitArray> {
|
||||
// bitArray is guaranteed to be a multiple of the wordSize, so no padding needed
|
||||
let message_size_in_words = bitArray.getSize() / wordSize;
|
||||
let message_size_in_words = bitArray.get_size() / wordSize;
|
||||
let mut rs = ReedSolomonEncoder::new(getGF(wordSize)?)?;
|
||||
let total_words = totalBits / wordSize;
|
||||
let mut message_words = bitsToWords(bitArray, wordSize, total_words);
|
||||
@@ -448,7 +448,7 @@ fn generateCheckWords(bitArray: &BitArray, totalBits: usize, wordSize: usize) ->
|
||||
fn bitsToWords(stuffedBits: &BitArray, wordSize: usize, totalWords: usize) -> Vec<i32> {
|
||||
let mut message = vec![0; totalWords];
|
||||
let mut i = 0;
|
||||
let n = stuffedBits.getSize() / wordSize;
|
||||
let n = stuffedBits.get_size() / wordSize;
|
||||
while i < n {
|
||||
// for (i = 0, n = stuffedBits.getSize() / wordSize; i < n; i++) {
|
||||
let mut value = 0;
|
||||
@@ -483,7 +483,7 @@ fn getGF(wordSize: usize) -> Result<GenericGFRef> {
|
||||
pub fn stuffBits(bits: &BitArray, word_size: usize) -> Result<BitArray> {
|
||||
let mut out = BitArray::new();
|
||||
|
||||
let n = bits.getSize() as isize;
|
||||
let n = bits.get_size() as isize;
|
||||
let mask = (1 << word_size) - 2;
|
||||
let mut i: isize = 0;
|
||||
while i < n {
|
||||
|
||||
@@ -21,7 +21,7 @@ pub fn toBitArray(bits: &str) -> BitArray {
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn toBooleanArray(bitArray: &BitArray) -> Vec<bool> {
|
||||
let mut result = vec![false; bitArray.getSize()];
|
||||
let mut result = vec![false; bitArray.get_size()];
|
||||
// for i in 0..result.len() {
|
||||
for (i, res) in result.iter_mut().enumerate() {
|
||||
// for (int i = 0; i < result.length; i++) {
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
//package com.google.zxing;
|
||||
|
||||
use std::{borrow::Cow, rc::Rc};
|
||||
use std::borrow::Cow;
|
||||
|
||||
use crate::{
|
||||
common::{BitArray, BitMatrix, Result},
|
||||
@@ -35,7 +35,9 @@ pub trait Binarizer {
|
||||
//private final LuminanceSource source;
|
||||
//fn new(source:dyn LuminanceSource) -> Self;
|
||||
|
||||
fn getLuminanceSource(&self) -> &Box<dyn LuminanceSource>;
|
||||
type Source: LuminanceSource;
|
||||
|
||||
fn get_luminance_source(&self) -> &Self::Source;
|
||||
|
||||
/**
|
||||
* Converts one row of luminance data to 1 bit data. May actually do the conversion, or return
|
||||
@@ -51,7 +53,7 @@ pub trait Binarizer {
|
||||
* @return The array of bits for this row (true means black).
|
||||
* @throws NotFoundException if row can't be binarized
|
||||
*/
|
||||
fn getBlackRow(&self, y: usize) -> Result<Cow<BitArray>>;
|
||||
fn get_black_row(&self, y: usize) -> Result<Cow<BitArray>>;
|
||||
|
||||
/**
|
||||
* Converts a 2D array of luminance data to 1 bit data. As above, assume this method is expensive
|
||||
@@ -62,7 +64,7 @@ pub trait Binarizer {
|
||||
* @return The 2D array of bits for the image (true means black).
|
||||
* @throws NotFoundException if image can't be binarized to make a matrix
|
||||
*/
|
||||
fn getBlackMatrix(&self) -> Result<&BitMatrix>;
|
||||
fn get_black_matrix(&self) -> Result<&BitMatrix>;
|
||||
|
||||
/**
|
||||
* Creates a new object with the same type as this Binarizer implementation, but with pristine
|
||||
@@ -72,9 +74,11 @@ pub trait Binarizer {
|
||||
* @param source The LuminanceSource this Binarizer will operate on.
|
||||
* @return A new concrete Binarizer implementation object.
|
||||
*/
|
||||
fn createBinarizer(&self, source: Box<dyn LuminanceSource>) -> Rc<dyn Binarizer>;
|
||||
fn create_binarizer(&self, source: Self::Source) -> Self
|
||||
where
|
||||
Self: Sized;
|
||||
|
||||
fn getWidth(&self) -> usize;
|
||||
fn get_width(&self) -> usize;
|
||||
|
||||
fn getHeight(&self) -> usize;
|
||||
fn get_height(&self) -> usize;
|
||||
}
|
||||
|
||||
@@ -16,11 +16,11 @@
|
||||
|
||||
//package com.google.zxing;
|
||||
|
||||
use std::{borrow::Cow, fmt, rc::Rc};
|
||||
use std::{borrow::Cow, fmt};
|
||||
|
||||
use crate::{
|
||||
common::{BitArray, BitMatrix, Result},
|
||||
Binarizer,
|
||||
Binarizer, LuminanceSource,
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -30,13 +30,13 @@ use crate::{
|
||||
* @author dswitkin@google.com (Daniel Switkin)
|
||||
*/
|
||||
|
||||
pub struct BinaryBitmap {
|
||||
binarizer: Rc<dyn Binarizer>,
|
||||
pub struct BinaryBitmap<B: Binarizer> {
|
||||
binarizer: B,
|
||||
matrix: Option<BitMatrix>,
|
||||
}
|
||||
|
||||
impl BinaryBitmap {
|
||||
pub fn new(binarizer: Rc<dyn Binarizer>) -> Self {
|
||||
impl<B: Binarizer> BinaryBitmap<B> {
|
||||
pub fn new(binarizer: B) -> Self {
|
||||
Self {
|
||||
matrix: None,
|
||||
binarizer,
|
||||
@@ -46,15 +46,15 @@ impl BinaryBitmap {
|
||||
/**
|
||||
* @return The width of the bitmap.
|
||||
*/
|
||||
pub fn getWidth(&self) -> usize {
|
||||
self.binarizer.getWidth()
|
||||
pub fn get_width(&self) -> usize {
|
||||
self.binarizer.get_width()
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The height of the bitmap.
|
||||
*/
|
||||
pub fn getHeight(&self) -> usize {
|
||||
self.binarizer.getHeight()
|
||||
pub fn get_height(&self) -> usize {
|
||||
self.binarizer.get_height()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -68,8 +68,8 @@ impl BinaryBitmap {
|
||||
* @return The array of bits for this row (true means black).
|
||||
* @throws NotFoundException if row can't be binarized
|
||||
*/
|
||||
pub fn getBlackRow(&self, y: usize) -> Result<Cow<BitArray>> {
|
||||
self.binarizer.getBlackRow(y)
|
||||
pub fn get_black_row(&self, y: usize) -> Result<Cow<BitArray>> {
|
||||
self.binarizer.get_black_row(y)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -83,14 +83,14 @@ impl BinaryBitmap {
|
||||
* @return The 2D array of bits for the image (true means black).
|
||||
* @throws NotFoundException if image can't be binarized to make a matrix
|
||||
*/
|
||||
pub fn getBlackMatrixMut(&mut self) -> &mut BitMatrix {
|
||||
pub fn get_black_matrix_mut(&mut self) -> &mut BitMatrix {
|
||||
// The matrix is created on demand the first time it is requested, then cached. There are two
|
||||
// reasons for this:
|
||||
// 1. This work will never be done if the caller only installs 1D Reader objects, or if a
|
||||
// 1D Reader finds a barcode before the 2D Readers run.
|
||||
// 2. This work will only be done once even if the caller installs multiple 2D Readers.
|
||||
if self.matrix.is_none() {
|
||||
self.matrix = Some(self.binarizer.getBlackMatrix().unwrap().clone());
|
||||
self.matrix = Some(self.binarizer.get_black_matrix().unwrap().clone());
|
||||
}
|
||||
self.matrix.as_mut().unwrap()
|
||||
}
|
||||
@@ -106,14 +106,14 @@ impl BinaryBitmap {
|
||||
* @return The 2D array of bits for the image (true means black).
|
||||
* @throws NotFoundException if image can't be binarized to make a matrix
|
||||
*/
|
||||
pub fn getBlackMatrix(&mut self) -> &BitMatrix {
|
||||
pub fn get_black_matrix(&mut self) -> &BitMatrix {
|
||||
// The matrix is created on demand the first time it is requested, then cached. There are two
|
||||
// reasons for this:
|
||||
// 1. This work will never be done if the caller only installs 1D Reader objects, or if a
|
||||
// 1D Reader finds a barcode before the 2D Readers run.
|
||||
// 2. This work will only be done once even if the caller installs multiple 2D Readers.
|
||||
if self.matrix.is_none() {
|
||||
self.matrix = Some(self.binarizer.getBlackMatrix().unwrap().clone())
|
||||
self.matrix = Some(self.binarizer.get_black_matrix().unwrap().clone())
|
||||
}
|
||||
self.matrix.as_ref().unwrap()
|
||||
}
|
||||
@@ -121,8 +121,8 @@ impl BinaryBitmap {
|
||||
/**
|
||||
* @return Whether this bitmap can be cropped.
|
||||
*/
|
||||
pub fn isCropSupported(&self) -> bool {
|
||||
self.binarizer.getLuminanceSource().isCropSupported()
|
||||
pub fn is_crop_supported(&self) -> bool {
|
||||
self.binarizer.get_luminance_source().is_crop_supported()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -137,22 +137,22 @@ impl BinaryBitmap {
|
||||
* @param height The height of the rectangle to crop.
|
||||
* @return A cropped version of this object.
|
||||
*/
|
||||
pub fn crop(&mut self, left: usize, top: usize, width: usize, height: usize) -> BinaryBitmap {
|
||||
pub fn crop(&mut self, left: usize, top: usize, width: usize, height: usize) -> Self {
|
||||
let newSource = self
|
||||
.binarizer
|
||||
.getLuminanceSource()
|
||||
.get_luminance_source()
|
||||
.crop(left, top, width, height);
|
||||
return BinaryBitmap::new(
|
||||
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)
|
||||
}
|
||||
|
||||
@@ -88,8 +88,8 @@ impl BufferedImageLuminanceSource {
|
||||
}
|
||||
|
||||
impl LuminanceSource for BufferedImageLuminanceSource {
|
||||
fn getRow(&self, y: usize) -> Vec<u8> {
|
||||
let width = self.getWidth(); // - self.left as usize;
|
||||
fn get_row(&self, y: usize) -> Vec<u8> {
|
||||
let width = self.get_width(); // - self.left as usize;
|
||||
|
||||
let pixels: Vec<u8> = || -> Option<Vec<u8>> {
|
||||
Some(
|
||||
@@ -108,7 +108,7 @@ impl LuminanceSource for BufferedImageLuminanceSource {
|
||||
pixels
|
||||
}
|
||||
|
||||
fn getMatrix(&self) -> Vec<u8> {
|
||||
fn get_matrix(&self) -> Vec<u8> {
|
||||
if self.height == self.image.height() as usize && self.width == self.image.width() as usize
|
||||
{
|
||||
return self.image.as_bytes().to_vec();
|
||||
@@ -141,56 +141,50 @@ impl LuminanceSource for BufferedImageLuminanceSource {
|
||||
data
|
||||
}
|
||||
|
||||
fn getWidth(&self) -> usize {
|
||||
fn get_width(&self) -> usize {
|
||||
self.width
|
||||
}
|
||||
|
||||
fn getHeight(&self) -> usize {
|
||||
fn get_height(&self) -> usize {
|
||||
self.height
|
||||
}
|
||||
|
||||
fn is_crop_supported(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn crop(&self, left: usize, top: usize, width: usize, height: usize) -> Result<Self> {
|
||||
Ok(Self {
|
||||
image: self.image.clone(),
|
||||
width,
|
||||
height,
|
||||
left: self.left + left as u32,
|
||||
top: self.top + top as u32,
|
||||
})
|
||||
}
|
||||
|
||||
fn is_rotate_supported(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn invert(&mut self) {
|
||||
let mut img = (*self.image).clone();
|
||||
img.invert();
|
||||
self.image = Rc::new(img);
|
||||
}
|
||||
|
||||
fn isCropSupported(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn crop(
|
||||
&self,
|
||||
left: usize,
|
||||
top: usize,
|
||||
width: usize,
|
||||
height: usize,
|
||||
) -> Result<Box<dyn LuminanceSource>> {
|
||||
Ok(Box::new(Self {
|
||||
image: self.image.clone(),
|
||||
width,
|
||||
height,
|
||||
left: self.left + left as u32,
|
||||
top: self.top + top as u32,
|
||||
}))
|
||||
}
|
||||
|
||||
fn isRotateSupported(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn rotateCounterClockwise(&self) -> Result<Box<dyn LuminanceSource>> {
|
||||
fn rotate_counter_clockwise(&self) -> Result<Self> {
|
||||
let img = self.image.rotate270();
|
||||
Ok(Box::new(Self {
|
||||
Ok(Self {
|
||||
width: img.width() as usize,
|
||||
height: img.height() as usize,
|
||||
image: Rc::new(img),
|
||||
left: 0,
|
||||
top: 0,
|
||||
}))
|
||||
})
|
||||
}
|
||||
|
||||
fn rotateCounterClockwise45(&self) -> Result<Box<dyn LuminanceSource>> {
|
||||
fn rotate_counter_clockwise_45(&self) -> Result<Self> {
|
||||
let img = rotate_about_center(
|
||||
&self.image.to_luma8(),
|
||||
MINUS_45_IN_RADIANS,
|
||||
@@ -200,12 +194,12 @@ impl LuminanceSource for BufferedImageLuminanceSource {
|
||||
|
||||
let new_img = DynamicImage::from(img);
|
||||
|
||||
Ok(Box::new(Self {
|
||||
Ok(Self {
|
||||
width: new_img.width() as usize,
|
||||
height: new_img.height() as usize,
|
||||
image: Rc::new(new_img),
|
||||
left: 0,
|
||||
top: 0,
|
||||
}))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,12 +43,12 @@ fn test_get_set() {
|
||||
#[test]
|
||||
fn test_get_next_set1() {
|
||||
let array = BitArray::with_size(32);
|
||||
for i in 0..array.getSize() {
|
||||
for i in 0..array.get_size() {
|
||||
// for (int i = 0; i < array.getSize(); i++) {
|
||||
assert_eq!(32, array.getNextSet(i), "{i}");
|
||||
}
|
||||
let array = BitArray::with_size(33);
|
||||
for i in 0..array.getSize() {
|
||||
for i in 0..array.get_size() {
|
||||
// for (int i = 0; i < array.getSize(); i++) {
|
||||
assert_eq!(33, array.getNextSet(i), "{i}");
|
||||
}
|
||||
@@ -58,13 +58,13 @@ fn test_get_next_set1() {
|
||||
fn test_get_next_set2() {
|
||||
let mut array = BitArray::with_size(33);
|
||||
array.set(31);
|
||||
for i in 0..array.getSize() {
|
||||
for i in 0..array.get_size() {
|
||||
// for (int i = 0; i < array.getSize(); i++) {
|
||||
assert_eq!(if i <= 31 { 31 } else { 33 }, array.getNextSet(i), "{i}");
|
||||
}
|
||||
array = BitArray::with_size(33);
|
||||
array.set(32);
|
||||
for i in 0..array.getSize() {
|
||||
for i in 0..array.get_size() {
|
||||
// for (int i = 0; i < array.getSize(); i++) {
|
||||
assert_eq!(32, array.getNextSet(i), "{i}");
|
||||
}
|
||||
@@ -75,7 +75,7 @@ fn test_get_next_set3() {
|
||||
let mut array = BitArray::with_size(63);
|
||||
array.set(31);
|
||||
array.set(32);
|
||||
for i in 0..array.getSize() {
|
||||
for i in 0..array.get_size() {
|
||||
// for (int i = 0; i < array.getSize(); i++) {
|
||||
let expected;
|
||||
if i <= 31 {
|
||||
@@ -94,7 +94,7 @@ fn test_get_next_set4() {
|
||||
let mut array = BitArray::with_size(63);
|
||||
array.set(33);
|
||||
array.set(40);
|
||||
for i in 0..array.getSize() {
|
||||
for i in 0..array.get_size() {
|
||||
// for (int i = 0; i < array.getSize(); i++) {
|
||||
let expected;
|
||||
if i <= 33 {
|
||||
@@ -117,14 +117,14 @@ fn test_get_next_set5() {
|
||||
let numSet = r.gen_range(0..20);
|
||||
for _j in 0..numSet {
|
||||
// for (int j = 0; j < numSet; j++) {
|
||||
array.set(r.gen_range(0..array.getSize()));
|
||||
array.set(r.gen_range(0..array.get_size()));
|
||||
}
|
||||
let numQueries = r.gen_range(0..20);
|
||||
for _j in 0..numQueries {
|
||||
// for (int j = 0; j < numQueries; j++) {
|
||||
let query = r.gen_range(0..array.getSize());
|
||||
let query = r.gen_range(0..array.get_size());
|
||||
let mut expected = query;
|
||||
while expected < array.getSize() && !array.get(expected) {
|
||||
while expected < array.get_size() && !array.get(expected) {
|
||||
expected += 1;
|
||||
}
|
||||
let actual = array.getNextSet(query);
|
||||
|
||||
@@ -57,7 +57,7 @@ impl BitArray {
|
||||
Self { bits, size }
|
||||
}
|
||||
|
||||
pub fn getSize(&self) -> usize {
|
||||
pub fn get_size(&self) -> usize {
|
||||
self.size
|
||||
}
|
||||
|
||||
|
||||
@@ -156,12 +156,12 @@ fn test_get_row() {
|
||||
|
||||
// Should allocate
|
||||
let array = matrix.getRow(2);
|
||||
assert_eq!(102, array.getSize());
|
||||
assert_eq!(102, array.get_size());
|
||||
|
||||
// Should reallocate
|
||||
// let mut array2 = BitArray::with_size(60);
|
||||
let array2 = matrix.getRow(2);
|
||||
assert_eq!(102, array2.getSize());
|
||||
assert_eq!(102, array2.get_size());
|
||||
|
||||
// Should use provided object, with original BitArray size
|
||||
// let mut array3 = BitArray::with_size(200);
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
// import com.google.zxing.LuminanceSource;
|
||||
// import com.google.zxing.NotFoundException;
|
||||
|
||||
use std::{borrow::Cow, rc::Rc};
|
||||
use std::borrow::Cow;
|
||||
|
||||
use once_cell::unsync::OnceCell;
|
||||
|
||||
@@ -29,6 +29,10 @@ use crate::{Binarizer, Exceptions, LuminanceSource};
|
||||
|
||||
use super::{BitArray, BitMatrix};
|
||||
|
||||
const LUMINANCE_BITS: usize = 5;
|
||||
const LUMINANCE_SHIFT: usize = 8 - LUMINANCE_BITS;
|
||||
const LUMINANCE_BUCKETS: usize = 1 << LUMINANCE_BITS;
|
||||
|
||||
/**
|
||||
* This Binarizer implementation uses the old ZXing global histogram approach. It is suitable
|
||||
* for low-end mobile devices which don't have enough CPU or memory to use a local thresholding
|
||||
@@ -40,34 +44,35 @@ use super::{BitArray, BitMatrix};
|
||||
* @author dswitkin@google.com (Daniel Switkin)
|
||||
* @author Sean Owen
|
||||
*/
|
||||
pub struct GlobalHistogramBinarizer {
|
||||
pub struct GlobalHistogramBinarizer<LS: LuminanceSource> {
|
||||
//_luminances: Vec<u8>,
|
||||
width: usize,
|
||||
height: usize,
|
||||
source: Box<dyn LuminanceSource>,
|
||||
source: LS,
|
||||
black_matrix: OnceCell<BitMatrix>,
|
||||
black_row_cache: Vec<OnceCell<BitArray>>,
|
||||
}
|
||||
|
||||
impl Binarizer for GlobalHistogramBinarizer {
|
||||
fn getLuminanceSource(&self) -> &Box<dyn LuminanceSource> {
|
||||
impl<LS: LuminanceSource> Binarizer for GlobalHistogramBinarizer<LS> {
|
||||
type Source = LS;
|
||||
|
||||
fn get_luminance_source(&self) -> &Self::Source {
|
||||
&self.source
|
||||
}
|
||||
|
||||
// Applies simple sharpening to the row data to improve performance of the 1D Readers.
|
||||
fn getBlackRow(&self, y: usize) -> Result<Cow<BitArray>> {
|
||||
fn get_black_row(&self, y: usize) -> Result<Cow<BitArray>> {
|
||||
let row = self.black_row_cache[y].get_or_try_init(|| {
|
||||
let source = self.getLuminanceSource();
|
||||
let width = source.getWidth();
|
||||
let source = self.get_luminance_source();
|
||||
let width = source.get_width();
|
||||
let mut row = BitArray::with_size(width);
|
||||
|
||||
// self.initArrays(width);
|
||||
let localLuminances = source.getRow(y);
|
||||
let mut localBuckets = [0; GlobalHistogramBinarizer::LUMINANCE_BUCKETS]; //self.buckets.clone();
|
||||
let localLuminances = source.get_row(y);
|
||||
let mut localBuckets = [0; LUMINANCE_BUCKETS]; //self.buckets.clone();
|
||||
for x in 0..width {
|
||||
// for (int x = 0; x < width; x++) {
|
||||
localBuckets[((localLuminances[x]) >> GlobalHistogramBinarizer::LUMINANCE_SHIFT)
|
||||
as usize] += 1;
|
||||
localBuckets[((localLuminances[x]) >> LUMINANCE_SHIFT) as usize] += 1;
|
||||
}
|
||||
let blackPoint = Self::estimateBlackPoint(&localBuckets)?;
|
||||
|
||||
@@ -102,63 +107,60 @@ impl Binarizer for GlobalHistogramBinarizer {
|
||||
}
|
||||
|
||||
// Does not sharpen the data, as this call is intended to only be used by 2D Readers.
|
||||
fn getBlackMatrix(&self) -> Result<&BitMatrix> {
|
||||
fn get_black_matrix(&self) -> Result<&BitMatrix> {
|
||||
let matrix = self
|
||||
.black_matrix
|
||||
.get_or_try_init(|| Self::build_black_matrix(&self.source))?;
|
||||
Ok(matrix)
|
||||
}
|
||||
|
||||
fn createBinarizer(&self, source: Box<dyn crate::LuminanceSource>) -> Rc<dyn Binarizer> {
|
||||
Rc::new(GlobalHistogramBinarizer::new(source))
|
||||
fn create_binarizer(&self, source: LS) -> Self {
|
||||
Self::new(source)
|
||||
}
|
||||
|
||||
fn getWidth(&self) -> usize {
|
||||
fn get_width(&self) -> usize {
|
||||
self.width
|
||||
}
|
||||
|
||||
fn getHeight(&self) -> usize {
|
||||
fn get_height(&self) -> usize {
|
||||
self.height
|
||||
}
|
||||
}
|
||||
|
||||
impl GlobalHistogramBinarizer {
|
||||
const LUMINANCE_BITS: usize = 5;
|
||||
const LUMINANCE_SHIFT: usize = 8 - GlobalHistogramBinarizer::LUMINANCE_BITS;
|
||||
const LUMINANCE_BUCKETS: usize = 1 << GlobalHistogramBinarizer::LUMINANCE_BITS;
|
||||
impl<LS: LuminanceSource> GlobalHistogramBinarizer<LS> {
|
||||
// const EMPTY: [u8; 0] = [0; 0];
|
||||
|
||||
pub fn new(source: Box<dyn LuminanceSource>) -> Self {
|
||||
pub fn new(source: LS) -> Self {
|
||||
Self {
|
||||
//_luminances: vec![0; source.getWidth()],
|
||||
width: source.getWidth(),
|
||||
height: source.getHeight(),
|
||||
width: source.get_width(),
|
||||
height: source.get_height(),
|
||||
black_matrix: OnceCell::new(),
|
||||
black_row_cache: vec![OnceCell::default(); source.getHeight()],
|
||||
black_row_cache: vec![OnceCell::default(); source.get_height()],
|
||||
source,
|
||||
}
|
||||
}
|
||||
|
||||
fn build_black_matrix(source: &Box<dyn LuminanceSource>) -> Result<BitMatrix> {
|
||||
fn build_black_matrix(source: &LS) -> Result<BitMatrix> {
|
||||
// let source = source.getLuminanceSource();
|
||||
let width = source.getWidth();
|
||||
let height = source.getHeight();
|
||||
let width = source.get_width();
|
||||
let height = source.get_height();
|
||||
let mut matrix = BitMatrix::new(width as u32, height as u32)?;
|
||||
|
||||
// Quickly calculates the histogram by sampling four rows from the image. This proved to be
|
||||
// more robust on the blackbox tests than sampling a diagonal as we used to do.
|
||||
// self.initArrays(width);
|
||||
let mut localBuckets = [0; GlobalHistogramBinarizer::LUMINANCE_BUCKETS]; //self.buckets.clone();
|
||||
let mut localBuckets = [0; LUMINANCE_BUCKETS]; //self.buckets.clone();
|
||||
for y in 1..5 {
|
||||
// for (int y = 1; y < 5; y++) {
|
||||
let row = height * y / 5;
|
||||
let localLuminances = source.getRow(row);
|
||||
let localLuminances = source.get_row(row);
|
||||
let right = (width * 4) / 5;
|
||||
let mut x = width / 5;
|
||||
while x < right {
|
||||
// for (int x = width / 5; x < right; x++) {
|
||||
let pixel = localLuminances[x];
|
||||
localBuckets[(pixel >> GlobalHistogramBinarizer::LUMINANCE_SHIFT) as usize] += 1;
|
||||
localBuckets[(pixel >> LUMINANCE_SHIFT) as usize] += 1;
|
||||
x += 1;
|
||||
}
|
||||
}
|
||||
@@ -167,7 +169,7 @@ impl GlobalHistogramBinarizer {
|
||||
// We delay reading the entire image luminance until the black point estimation succeeds.
|
||||
// Although we end up reading four rows twice, it is consistent with our motto of
|
||||
// "fail quickly" which is necessary for continuous scanning.
|
||||
let localLuminances = source.getMatrix();
|
||||
let localLuminances = source.get_matrix();
|
||||
for y in 0..height {
|
||||
// for (int y = 0; y < height; y++) {
|
||||
let offset = y * width;
|
||||
@@ -255,6 +257,6 @@ impl GlobalHistogramBinarizer {
|
||||
x -= 1;
|
||||
}
|
||||
|
||||
Ok((bestValley as u32) << GlobalHistogramBinarizer::LUMINANCE_SHIFT)
|
||||
Ok((bestValley as u32) << LUMINANCE_SHIFT)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
// import com.google.zxing.LuminanceSource;
|
||||
// import com.google.zxing.NotFoundException;
|
||||
|
||||
use std::{borrow::Cow, rc::Rc};
|
||||
use std::borrow::Cow;
|
||||
|
||||
use once_cell::unsync::OnceCell;
|
||||
|
||||
@@ -46,20 +46,22 @@ use super::{BitArray, BitMatrix, GlobalHistogramBinarizer};
|
||||
*
|
||||
* @author dswitkin@google.com (Daniel Switkin)
|
||||
*/
|
||||
pub struct HybridBinarizer {
|
||||
pub struct HybridBinarizer<LS: LuminanceSource> {
|
||||
//width: usize,
|
||||
//height: usize,
|
||||
//source: Box<dyn LuminanceSource>,
|
||||
ghb: GlobalHistogramBinarizer,
|
||||
ghb: GlobalHistogramBinarizer<LS>,
|
||||
black_matrix: OnceCell<BitMatrix>,
|
||||
}
|
||||
impl Binarizer for HybridBinarizer {
|
||||
fn getLuminanceSource(&self) -> &Box<dyn LuminanceSource> {
|
||||
self.ghb.getLuminanceSource()
|
||||
impl<LS: LuminanceSource> Binarizer for HybridBinarizer<LS> {
|
||||
type Source = LS;
|
||||
|
||||
fn get_luminance_source(&self) -> &LS {
|
||||
self.ghb.get_luminance_source()
|
||||
}
|
||||
|
||||
fn getBlackRow(&self, y: usize) -> Result<Cow<BitArray>> {
|
||||
self.ghb.getBlackRow(y)
|
||||
fn get_black_row(&self, y: usize) -> Result<Cow<BitArray>> {
|
||||
self.ghb.get_black_row(y)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -67,35 +69,36 @@ impl Binarizer for HybridBinarizer {
|
||||
* constructor instead, but there are some advantages to doing it lazily, such as making
|
||||
* profiling easier, and not doing heavy lifting when callers don't expect it.
|
||||
*/
|
||||
fn getBlackMatrix(&self) -> Result<&BitMatrix> {
|
||||
fn get_black_matrix(&self) -> Result<&BitMatrix> {
|
||||
let matrix = self
|
||||
.black_matrix
|
||||
.get_or_try_init(|| Self::calculateBlackMatrix(&self.ghb))?;
|
||||
Ok(matrix)
|
||||
}
|
||||
|
||||
fn createBinarizer(&self, source: Box<dyn LuminanceSource>) -> Rc<dyn Binarizer> {
|
||||
Rc::new(HybridBinarizer::new(source))
|
||||
fn create_binarizer(&self, source: LS) -> Self {
|
||||
Self::new(source)
|
||||
}
|
||||
|
||||
fn getWidth(&self) -> usize {
|
||||
self.ghb.getWidth()
|
||||
fn get_width(&self) -> usize {
|
||||
self.ghb.get_width()
|
||||
}
|
||||
|
||||
fn getHeight(&self) -> usize {
|
||||
self.ghb.getHeight()
|
||||
fn get_height(&self) -> usize {
|
||||
self.ghb.get_height()
|
||||
}
|
||||
}
|
||||
impl HybridBinarizer {
|
||||
// This class uses 5x5 blocks to compute local luminance, where each block is 8x8 pixels.
|
||||
// So this is the smallest dimension in each axis we can accept.
|
||||
const BLOCK_SIZE_POWER: usize = 3;
|
||||
const BLOCK_SIZE: usize = 1 << HybridBinarizer::BLOCK_SIZE_POWER; // ...0100...00
|
||||
const BLOCK_SIZE_MASK: usize = HybridBinarizer::BLOCK_SIZE - 1; // ...0011...11
|
||||
const MINIMUM_DIMENSION: usize = HybridBinarizer::BLOCK_SIZE * 5;
|
||||
const MIN_DYNAMIC_RANGE: usize = 24;
|
||||
|
||||
pub fn new(source: Box<dyn LuminanceSource>) -> Self {
|
||||
// This class uses 5x5 blocks to compute local luminance, where each block is 8x8 pixels.
|
||||
// So this is the smallest dimension in each axis we can accept.
|
||||
const BLOCK_SIZE_POWER: usize = 3;
|
||||
const BLOCK_SIZE: usize = 1 << BLOCK_SIZE_POWER; // ...0100...00
|
||||
const BLOCK_SIZE_MASK: usize = BLOCK_SIZE - 1; // ...0011...11
|
||||
const MINIMUM_DIMENSION: usize = BLOCK_SIZE * 5;
|
||||
const MIN_DYNAMIC_RANGE: usize = 24;
|
||||
|
||||
impl<LS: LuminanceSource> HybridBinarizer<LS> {
|
||||
pub fn new(source: LS) -> Self {
|
||||
let ghb = GlobalHistogramBinarizer::new(source);
|
||||
Self {
|
||||
black_matrix: OnceCell::new(),
|
||||
@@ -103,21 +106,21 @@ impl HybridBinarizer {
|
||||
}
|
||||
}
|
||||
|
||||
fn calculateBlackMatrix(ghb: &GlobalHistogramBinarizer) -> Result<BitMatrix> {
|
||||
fn calculateBlackMatrix<LS2: LuminanceSource>(
|
||||
ghb: &GlobalHistogramBinarizer<LS2>,
|
||||
) -> Result<BitMatrix> {
|
||||
// let matrix;
|
||||
let source = ghb.getLuminanceSource();
|
||||
let width = source.getWidth();
|
||||
let height = source.getHeight();
|
||||
let matrix = if width >= HybridBinarizer::MINIMUM_DIMENSION
|
||||
&& height >= HybridBinarizer::MINIMUM_DIMENSION
|
||||
{
|
||||
let luminances = source.getMatrix();
|
||||
let mut sub_width = width >> HybridBinarizer::BLOCK_SIZE_POWER;
|
||||
if (width & HybridBinarizer::BLOCK_SIZE_MASK) != 0 {
|
||||
let source = ghb.get_luminance_source();
|
||||
let width = source.get_width();
|
||||
let height = source.get_height();
|
||||
let matrix = if width >= MINIMUM_DIMENSION && height >= MINIMUM_DIMENSION {
|
||||
let luminances = source.get_matrix();
|
||||
let mut sub_width = width >> BLOCK_SIZE_POWER;
|
||||
if (width & BLOCK_SIZE_MASK) != 0 {
|
||||
sub_width += 1;
|
||||
}
|
||||
let mut sub_height = height >> HybridBinarizer::BLOCK_SIZE_POWER;
|
||||
if (height & HybridBinarizer::BLOCK_SIZE_MASK) != 0 {
|
||||
let mut sub_height = height >> BLOCK_SIZE_POWER;
|
||||
if (height & BLOCK_SIZE_MASK) != 0 {
|
||||
sub_height += 1;
|
||||
}
|
||||
let black_points = Self::calculateBlackPoints(
|
||||
@@ -141,7 +144,7 @@ impl HybridBinarizer {
|
||||
Ok(new_matrix)
|
||||
} else {
|
||||
// If the image is too small, fall back to the global histogram approach.
|
||||
let m = ghb.getBlackMatrix()?;
|
||||
let m = ghb.get_black_matrix()?;
|
||||
Ok(m.clone())
|
||||
};
|
||||
// dbg!(matrix.to_string());
|
||||
@@ -162,18 +165,18 @@ impl HybridBinarizer {
|
||||
black_points: &[Vec<u32>],
|
||||
matrix: &mut BitMatrix,
|
||||
) {
|
||||
let maxYOffset = height - HybridBinarizer::BLOCK_SIZE as u32;
|
||||
let maxXOffset = width - HybridBinarizer::BLOCK_SIZE as u32;
|
||||
let maxYOffset = height - BLOCK_SIZE as u32;
|
||||
let maxXOffset = width - BLOCK_SIZE as u32;
|
||||
for y in 0..sub_height {
|
||||
// for (int y = 0; y < subHeight; y++) {
|
||||
let mut yoffset = y << HybridBinarizer::BLOCK_SIZE_POWER;
|
||||
let mut yoffset = y << BLOCK_SIZE_POWER;
|
||||
if yoffset > maxYOffset {
|
||||
yoffset = maxYOffset;
|
||||
}
|
||||
let top = Self::cap(y, sub_height - 3);
|
||||
for x in 0..sub_width {
|
||||
// for (int x = 0; x < subWidth; x++) {
|
||||
let mut xoffset = x << HybridBinarizer::BLOCK_SIZE_POWER;
|
||||
let mut xoffset = x << BLOCK_SIZE_POWER;
|
||||
if xoffset > maxXOffset {
|
||||
xoffset = maxXOffset;
|
||||
}
|
||||
@@ -215,9 +218,9 @@ impl HybridBinarizer {
|
||||
matrix: &mut BitMatrix,
|
||||
) {
|
||||
let mut offset = yoffset * stride + xoffset;
|
||||
for y in 0..HybridBinarizer::BLOCK_SIZE {
|
||||
for y in 0..BLOCK_SIZE {
|
||||
// for (int y = 0, offset = yoffset * stride + xoffset; y < HybridBinarizer::BLOCK_SIZE; y++, offset += stride) {
|
||||
for x in 0..HybridBinarizer::BLOCK_SIZE {
|
||||
for x in 0..BLOCK_SIZE {
|
||||
// for (int x = 0; x < HybridBinarizer::BLOCK_SIZE; x++) {
|
||||
// Comparison needs to be <= so that black == 0 pixels are black even if the threshold is 0.
|
||||
if luminances[offset as usize + x] as u32 <= threshold {
|
||||
@@ -240,18 +243,18 @@ impl HybridBinarizer {
|
||||
width: u32,
|
||||
height: u32,
|
||||
) -> Vec<Vec<u32>> {
|
||||
let maxYOffset = height as usize - HybridBinarizer::BLOCK_SIZE;
|
||||
let maxXOffset = width as usize - HybridBinarizer::BLOCK_SIZE;
|
||||
let maxYOffset = height as usize - BLOCK_SIZE;
|
||||
let maxXOffset = width as usize - BLOCK_SIZE;
|
||||
let mut blackPoints = vec![vec![0; subWidth as usize]; subHeight as usize];
|
||||
for y in 0..subHeight {
|
||||
// for (int y = 0; y < subHeight; y++) {
|
||||
let mut yoffset = y << HybridBinarizer::BLOCK_SIZE_POWER;
|
||||
let mut yoffset = y << BLOCK_SIZE_POWER;
|
||||
if yoffset > maxYOffset as u32 {
|
||||
yoffset = maxYOffset as u32;
|
||||
}
|
||||
for x in 0..subWidth {
|
||||
// for (int x = 0; x < subWidth; x++) {
|
||||
let mut xoffset = x << HybridBinarizer::BLOCK_SIZE_POWER;
|
||||
let mut xoffset = x << BLOCK_SIZE_POWER;
|
||||
if xoffset > maxXOffset as u32 {
|
||||
xoffset = maxXOffset as u32;
|
||||
}
|
||||
@@ -261,9 +264,9 @@ impl HybridBinarizer {
|
||||
|
||||
let mut offset = yoffset * width + xoffset;
|
||||
let mut yy = 0;
|
||||
while yy < HybridBinarizer::BLOCK_SIZE {
|
||||
while yy < BLOCK_SIZE {
|
||||
// for (int yy = 0, offset = yoffset * width + xoffset; yy < HybridBinarizer::BLOCK_SIZE; yy++, offset += width) {
|
||||
for xx in 0..HybridBinarizer::BLOCK_SIZE {
|
||||
for xx in 0..BLOCK_SIZE {
|
||||
// for (int xx = 0; xx < HybridBinarizer::BLOCK_SIZE; xx++) {
|
||||
let pixel = luminances[offset as usize + xx];
|
||||
sum += pixel as u32;
|
||||
@@ -276,13 +279,13 @@ impl HybridBinarizer {
|
||||
}
|
||||
}
|
||||
// short-circuit min/max tests once dynamic range is met
|
||||
if (max - min) as usize > HybridBinarizer::MIN_DYNAMIC_RANGE {
|
||||
if (max - min) as usize > MIN_DYNAMIC_RANGE {
|
||||
// finish the rest of the rows quickly
|
||||
offset += width;
|
||||
yy += 1;
|
||||
while yy < HybridBinarizer::BLOCK_SIZE {
|
||||
while yy < BLOCK_SIZE {
|
||||
// for (yy++, offset += width; yy < HybridBinarizer::BLOCK_SIZE; yy++, offset += width) {
|
||||
for xx in 0..HybridBinarizer::BLOCK_SIZE {
|
||||
for xx in 0..BLOCK_SIZE {
|
||||
// for (int xx = 0; xx < BLOCK_SIZE; xx++) {
|
||||
sum += luminances[offset as usize + xx] as u32;
|
||||
}
|
||||
@@ -296,8 +299,8 @@ impl HybridBinarizer {
|
||||
}
|
||||
|
||||
// The default estimate is the average of the values in the block.
|
||||
let mut average = sum >> (HybridBinarizer::BLOCK_SIZE_POWER * 2);
|
||||
if (max - min) as usize <= HybridBinarizer::MIN_DYNAMIC_RANGE {
|
||||
let mut average = sum >> (BLOCK_SIZE_POWER * 2);
|
||||
if (max - min) as usize <= MIN_DYNAMIC_RANGE {
|
||||
// If variation within the block is low, assume this is a block with only light or only
|
||||
// dark pixels. In that case we do not want to use the average, as it would divide this
|
||||
// low contrast area into black and white pixels, essentially creating data out of noise.
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ use std::collections::HashMap;
|
||||
|
||||
use crate::{
|
||||
common::{BitMatrix, DecoderRXingResult, DetectorRXingResult, Result},
|
||||
BarcodeFormat, DecodeHintType, DecodeHintValue, Exceptions, RXingResult,
|
||||
BarcodeFormat, Binarizer, DecodeHintType, DecodeHintValue, Exceptions, RXingResult,
|
||||
RXingResultMetadataType, RXingResultMetadataValue, Reader,
|
||||
};
|
||||
|
||||
@@ -52,7 +52,10 @@ impl Reader for DataMatrixReader {
|
||||
* @throws FormatException if a Data Matrix code cannot be decoded
|
||||
* @throws ChecksumException if error correction fails
|
||||
*/
|
||||
fn decode(&mut self, image: &mut crate::BinaryBitmap) -> Result<crate::RXingResult> {
|
||||
fn decode<B: Binarizer>(
|
||||
&mut self,
|
||||
image: &mut crate::BinaryBitmap<B>,
|
||||
) -> Result<crate::RXingResult> {
|
||||
self.decode_with_hints(image, &HashMap::new())
|
||||
}
|
||||
|
||||
@@ -64,9 +67,9 @@ impl Reader for DataMatrixReader {
|
||||
* @throws FormatException if a Data Matrix code cannot be decoded
|
||||
* @throws ChecksumException if error correction fails
|
||||
*/
|
||||
fn decode_with_hints(
|
||||
fn decode_with_hints<B: Binarizer>(
|
||||
&mut self,
|
||||
image: &mut crate::BinaryBitmap,
|
||||
image: &mut crate::BinaryBitmap<B>,
|
||||
hints: &crate::DecodingHintDictionary,
|
||||
) -> Result<crate::RXingResult> {
|
||||
let try_harder = matches!(
|
||||
@@ -76,14 +79,14 @@ impl Reader for DataMatrixReader {
|
||||
let decoderRXingResult;
|
||||
let mut points = Vec::new();
|
||||
if hints.contains_key(&DecodeHintType::PURE_BARCODE) {
|
||||
let bits = self.extractPureBits(image.getBlackMatrix())?;
|
||||
let bits = self.extractPureBits(image.get_black_matrix())?;
|
||||
decoderRXingResult = DECODER.decode(&bits)?;
|
||||
points.clear();
|
||||
} else {
|
||||
//Result<DatamatrixDetectorResult, Exceptions>
|
||||
decoderRXingResult = if let Ok(fnd) = || -> Result<DecoderRXingResult> {
|
||||
let detectorRXingResult =
|
||||
zxing_cpp_detector::detect(image.getBlackMatrix(), try_harder, true)?;
|
||||
zxing_cpp_detector::detect(image.get_black_matrix(), try_harder, true)?;
|
||||
let decoded = DECODER.decode(detectorRXingResult.getBits())?;
|
||||
points = detectorRXingResult.getPoints().to_vec();
|
||||
Ok(decoded)
|
||||
@@ -91,14 +94,14 @@ impl Reader for DataMatrixReader {
|
||||
fnd
|
||||
} else if try_harder {
|
||||
if let Ok(fnd) = || -> Result<DecoderRXingResult> {
|
||||
let detectorRXingResult = Detector::new(image.getBlackMatrix())?.detect()?;
|
||||
let detectorRXingResult = Detector::new(image.get_black_matrix())?.detect()?;
|
||||
let decoded = DECODER.decode(detectorRXingResult.getBits())?;
|
||||
points = detectorRXingResult.getPoints().to_vec();
|
||||
Ok(decoded)
|
||||
}() {
|
||||
fnd
|
||||
} else {
|
||||
let bits = self.extractPureBits(image.getBlackMatrix())?;
|
||||
let bits = self.extractPureBits(image.get_black_matrix())?;
|
||||
DECODER.decode(&bits)?
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -2,7 +2,6 @@ use std::{
|
||||
collections::{HashMap, HashSet},
|
||||
io::Write,
|
||||
path::PathBuf,
|
||||
rc::Rc,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
@@ -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,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ pub struct Luma8LuminanceSource {
|
||||
original_dimension: (u32, u32),
|
||||
}
|
||||
impl LuminanceSource for Luma8LuminanceSource {
|
||||
fn getRow(&self, y: usize) -> Vec<u8> {
|
||||
fn get_row(&self, y: usize) -> Vec<u8> {
|
||||
self.data
|
||||
.chunks_exact(self.original_dimension.0 as usize)
|
||||
.skip(y + self.origin.1 as usize)
|
||||
@@ -27,7 +27,7 @@ impl LuminanceSource for Luma8LuminanceSource {
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn getMatrix(&self) -> Vec<u8> {
|
||||
fn get_matrix(&self) -> Vec<u8> {
|
||||
self.data
|
||||
.iter()
|
||||
.skip((self.original_dimension.0 * self.origin.1) as usize)
|
||||
@@ -38,7 +38,7 @@ impl LuminanceSource for Luma8LuminanceSource {
|
||||
.flat_map(|f| {
|
||||
f.iter()
|
||||
.skip((self.origin.0) as usize)
|
||||
.take(self.getWidth())
|
||||
.take(self.get_width())
|
||||
.copied()
|
||||
}) // flatten this all out
|
||||
.copied() // copy it over so that it's u8
|
||||
@@ -46,11 +46,11 @@ impl LuminanceSource for Luma8LuminanceSource {
|
||||
.collect() // collect into a vec
|
||||
}
|
||||
|
||||
fn getWidth(&self) -> usize {
|
||||
fn get_width(&self) -> usize {
|
||||
self.dimensions.0 as usize
|
||||
}
|
||||
|
||||
fn getHeight(&self) -> usize {
|
||||
fn get_height(&self) -> usize {
|
||||
self.dimensions.1 as usize
|
||||
}
|
||||
|
||||
@@ -58,31 +58,25 @@ impl LuminanceSource for Luma8LuminanceSource {
|
||||
self.inverted = !self.inverted;
|
||||
}
|
||||
|
||||
fn isCropSupported(&self) -> bool {
|
||||
fn is_crop_supported(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn crop(
|
||||
&self,
|
||||
left: usize,
|
||||
top: usize,
|
||||
width: usize,
|
||||
height: usize,
|
||||
) -> Result<Box<dyn LuminanceSource>> {
|
||||
Ok(Box::new(Self {
|
||||
fn crop(&self, left: usize, top: usize, width: usize, height: usize) -> Result<Self> {
|
||||
Ok(Self {
|
||||
dimensions: (width as u32, height as u32),
|
||||
origin: (left as u32, top as u32),
|
||||
data: self.data.clone(),
|
||||
inverted: self.inverted,
|
||||
original_dimension: self.original_dimension,
|
||||
}))
|
||||
})
|
||||
}
|
||||
|
||||
fn isRotateSupported(&self) -> bool {
|
||||
fn is_rotate_supported(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn rotateCounterClockwise(&self) -> Result<Box<dyn LuminanceSource>> {
|
||||
fn rotate_counter_clockwise(&self) -> Result<Self> {
|
||||
let mut new_matrix = Self {
|
||||
dimensions: self.dimensions,
|
||||
origin: self.origin,
|
||||
@@ -92,10 +86,10 @@ impl LuminanceSource for Luma8LuminanceSource {
|
||||
};
|
||||
new_matrix.transpose();
|
||||
new_matrix.reverseColumns();
|
||||
Ok(Box::new(new_matrix))
|
||||
Ok(new_matrix)
|
||||
}
|
||||
|
||||
fn rotateCounterClockwise45(&self) -> Result<Box<dyn LuminanceSource>> {
|
||||
fn rotate_counter_clockwise_45(&self) -> Result<Self> {
|
||||
Err(crate::Exceptions::unsupported_operation_with(
|
||||
"This luminance source does not support rotation by 45 degrees.",
|
||||
))
|
||||
@@ -104,12 +98,12 @@ impl LuminanceSource for Luma8LuminanceSource {
|
||||
|
||||
impl Luma8LuminanceSource {
|
||||
fn reverseColumns(&mut self) {
|
||||
for i in 0..self.getWidth() {
|
||||
for i in 0..self.get_width() {
|
||||
let mut j = 0;
|
||||
let mut k = self.getWidth() - 1;
|
||||
let mut k = self.get_width() - 1;
|
||||
while j < k {
|
||||
let offset_a = (self.getWidth() * i) + j;
|
||||
let offset_b = (self.getWidth() * i) + k;
|
||||
let offset_a = (self.get_width() * i) + j;
|
||||
let offset_b = (self.get_width() * i) + k;
|
||||
self.data.swap(offset_a, offset_b);
|
||||
j += 1;
|
||||
k -= 1;
|
||||
@@ -118,10 +112,10 @@ impl Luma8LuminanceSource {
|
||||
}
|
||||
|
||||
fn transpose(&mut self) {
|
||||
for i in 0..self.getHeight() {
|
||||
for j in i..self.getWidth() {
|
||||
let offset_a = (self.getWidth() * i) + j;
|
||||
let offset_b = (self.getWidth() * j) + i;
|
||||
for i in 0..self.get_height() {
|
||||
for j in i..self.get_width() {
|
||||
let offset_a = (self.get_width() * i) + j;
|
||||
let offset_b = (self.get_width() * j) + i;
|
||||
self.data.swap(offset_a, offset_b);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ pub trait LuminanceSource {
|
||||
* Always use the returned object, and ignore the .length of the array.
|
||||
* @return An array containing the luminance data.
|
||||
*/
|
||||
fn getRow(&self, y: usize) -> Vec<u8>;
|
||||
fn get_row(&self, y: usize) -> Vec<u8>;
|
||||
|
||||
/**
|
||||
* Fetches luminance data for the underlying bitmap. Values should be fetched using:
|
||||
@@ -56,22 +56,22 @@ pub trait LuminanceSource {
|
||||
* larger than width * height bytes on some platforms. Do not modify the contents
|
||||
* of the result.
|
||||
*/
|
||||
fn getMatrix(&self) -> Vec<u8>;
|
||||
fn get_matrix(&self) -> Vec<u8>;
|
||||
|
||||
/**
|
||||
* @return The width of the bitmap.
|
||||
*/
|
||||
fn getWidth(&self) -> usize;
|
||||
fn get_width(&self) -> usize;
|
||||
|
||||
/**
|
||||
* @return The height of the bitmap.
|
||||
*/
|
||||
fn getHeight(&self) -> usize;
|
||||
fn get_height(&self) -> usize;
|
||||
|
||||
/**
|
||||
* @return Whether this subclass supports cropping.
|
||||
*/
|
||||
fn isCropSupported(&self) -> bool {
|
||||
fn is_crop_supported(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
@@ -85,13 +85,10 @@ pub trait LuminanceSource {
|
||||
* @param height The height of the rectangle to crop.
|
||||
* @return A cropped version of this object.
|
||||
*/
|
||||
fn crop(
|
||||
&self,
|
||||
_left: usize,
|
||||
_top: usize,
|
||||
_width: usize,
|
||||
_height: usize,
|
||||
) -> Result<Box<dyn LuminanceSource>> {
|
||||
fn crop(&self, _left: usize, _top: usize, _width: usize, _height: usize) -> Result<Self>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
Err(Exceptions::unsupported_operation_with(
|
||||
"This luminance source does not support cropping.",
|
||||
))
|
||||
@@ -100,7 +97,7 @@ pub trait LuminanceSource {
|
||||
/**
|
||||
* @return Whether this subclass supports counter-clockwise rotation.
|
||||
*/
|
||||
fn isRotateSupported(&self) -> bool {
|
||||
fn is_rotate_supported(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
@@ -118,7 +115,10 @@ pub trait LuminanceSource {
|
||||
*
|
||||
* @return A rotated version of this object.
|
||||
*/
|
||||
fn rotateCounterClockwise(&self) -> Result<Box<dyn LuminanceSource>> {
|
||||
fn rotate_counter_clockwise(&self) -> Result<Self>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
Err(Exceptions::unsupported_operation_with(
|
||||
"This luminance source does not support rotation by 90 degrees.",
|
||||
))
|
||||
@@ -130,7 +130,10 @@ pub trait LuminanceSource {
|
||||
*
|
||||
* @return A rotated version of this object.
|
||||
*/
|
||||
fn rotateCounterClockwise45(&self) -> Result<Box<dyn LuminanceSource>> {
|
||||
fn rotate_counter_clockwise_45(&self) -> Result<Self>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
Err(Exceptions::unsupported_operation_with(
|
||||
"This luminance source does not support rotation by 45 degrees.",
|
||||
))
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -18,7 +18,7 @@ use std::collections::HashMap;
|
||||
|
||||
use crate::{
|
||||
common::{BitMatrix, DetectorRXingResult, Result},
|
||||
BarcodeFormat, DecodeHintType, DecodeHintValue, Exceptions, RXingResult,
|
||||
BarcodeFormat, Binarizer, DecodeHintType, DecodeHintValue, Exceptions, RXingResult,
|
||||
RXingResultMetadataType, Reader,
|
||||
};
|
||||
|
||||
@@ -41,7 +41,10 @@ impl Reader for MaxiCodeReader {
|
||||
* @throws FormatException if a MaxiCode cannot be decoded
|
||||
* @throws ChecksumException if error correction fails
|
||||
*/
|
||||
fn decode(&mut self, image: &mut crate::BinaryBitmap) -> Result<crate::RXingResult> {
|
||||
fn decode<B: Binarizer>(
|
||||
&mut self,
|
||||
image: &mut crate::BinaryBitmap<B>,
|
||||
) -> Result<crate::RXingResult> {
|
||||
self.decode_with_hints(image, &HashMap::new())
|
||||
}
|
||||
|
||||
@@ -53,9 +56,9 @@ impl Reader for MaxiCodeReader {
|
||||
* @throws FormatException if a MaxiCode cannot be decoded
|
||||
* @throws ChecksumException if error correction fails
|
||||
*/
|
||||
fn decode_with_hints(
|
||||
fn decode_with_hints<B: Binarizer>(
|
||||
&mut self,
|
||||
image: &mut crate::BinaryBitmap,
|
||||
image: &mut crate::BinaryBitmap<B>,
|
||||
hints: &crate::DecodingHintDictionary,
|
||||
) -> Result<crate::RXingResult> {
|
||||
// Note that MaxiCode reader effectively always assumes PURE_BARCODE mode
|
||||
@@ -68,12 +71,12 @@ impl Reader for MaxiCodeReader {
|
||||
let mut rotation = None;
|
||||
|
||||
let decoderRXingResult = if try_harder {
|
||||
let result = detector::detect(image.getBlackMatrixMut(), try_harder)?;
|
||||
let result = detector::detect(image.get_black_matrix_mut(), try_harder)?;
|
||||
rotation = Some(result.rotation());
|
||||
let parsed_result = detector::read_bits(result.getBits())?;
|
||||
maxicode_decoder::decode_with_hints(&parsed_result, hints)?
|
||||
} else {
|
||||
let bits = Self::extractPureBits(image.getBlackMatrix())?;
|
||||
let bits = Self::extractPureBits(image.get_black_matrix())?;
|
||||
maxicode_decoder::decode_with_hints(&bits, hints)?
|
||||
};
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use crate::common::Result;
|
||||
use crate::{point, Exceptions, Point, RXingResult, Reader};
|
||||
use crate::{point, Binarizer, Exceptions, Point, RXingResult, Reader};
|
||||
|
||||
/**
|
||||
* This class attempts to decode a barcode from an image, not by scanning the whole image,
|
||||
@@ -30,17 +30,17 @@ use crate::{point, Exceptions, Point, RXingResult, Reader};
|
||||
*/
|
||||
pub struct ByQuadrantReader<T: Reader>(T);
|
||||
impl<T: Reader> Reader for ByQuadrantReader<T> {
|
||||
fn decode(&mut self, image: &mut crate::BinaryBitmap) -> Result<crate::RXingResult> {
|
||||
fn decode<B: Binarizer>(&mut self, image: &mut crate::BinaryBitmap<B>) -> Result<RXingResult> {
|
||||
self.decode_with_hints(image, &HashMap::new())
|
||||
}
|
||||
|
||||
fn decode_with_hints(
|
||||
fn decode_with_hints<B: Binarizer>(
|
||||
&mut self,
|
||||
image: &mut crate::BinaryBitmap,
|
||||
image: &mut crate::BinaryBitmap<B>,
|
||||
hints: &crate::DecodingHintDictionary,
|
||||
) -> Result<crate::RXingResult> {
|
||||
let width = image.getWidth();
|
||||
let height = image.getHeight();
|
||||
let width = image.get_width();
|
||||
let height = image.get_height();
|
||||
let halfWidth = width / 2;
|
||||
let halfHeight = height / 2;
|
||||
|
||||
|
||||
@@ -17,8 +17,8 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use crate::{
|
||||
common::Result, point, BinaryBitmap, DecodingHintDictionary, Exceptions, Point, RXingResult,
|
||||
Reader,
|
||||
common::Result, point, Binarizer, BinaryBitmap, DecodingHintDictionary, Exceptions, Point,
|
||||
RXingResult, Reader,
|
||||
};
|
||||
|
||||
use super::MultipleBarcodeReader;
|
||||
@@ -41,20 +41,20 @@ use super::MultipleBarcodeReader;
|
||||
pub struct GenericMultipleBarcodeReader<T: Reader>(T);
|
||||
|
||||
impl<T: Reader> MultipleBarcodeReader for GenericMultipleBarcodeReader<T> {
|
||||
fn decode_multiple(
|
||||
fn decode_multiple<B: Binarizer>(
|
||||
&mut self,
|
||||
image: &mut crate::BinaryBitmap,
|
||||
) -> Result<Vec<crate::RXingResult>> {
|
||||
image: &mut BinaryBitmap<B>,
|
||||
) -> Result<Vec<RXingResult>> {
|
||||
self.decode_multiple_with_hints(image, &HashMap::new())
|
||||
}
|
||||
|
||||
fn decode_multiple_with_hints(
|
||||
fn decode_multiple_with_hints<B: Binarizer>(
|
||||
&mut self,
|
||||
image: &mut crate::BinaryBitmap,
|
||||
hints: &crate::DecodingHintDictionary,
|
||||
) -> Result<Vec<crate::RXingResult>> {
|
||||
image: &mut BinaryBitmap<B>,
|
||||
hints: &DecodingHintDictionary,
|
||||
) -> Result<Vec<RXingResult>> {
|
||||
let mut results = Vec::new();
|
||||
self.doDecodeMultiple(image, hints, &mut results, 0, 0, 0);
|
||||
self.do_decode_multiple(image, hints, &mut results, 0, 0, 0);
|
||||
if results.is_empty() {
|
||||
return Err(Exceptions::NOT_FOUND);
|
||||
}
|
||||
@@ -69,9 +69,9 @@ impl<T: Reader> GenericMultipleBarcodeReader<T> {
|
||||
Self(delegate)
|
||||
}
|
||||
|
||||
fn doDecodeMultiple(
|
||||
fn do_decode_multiple<B: Binarizer>(
|
||||
&mut self,
|
||||
image: &mut BinaryBitmap,
|
||||
image: &mut BinaryBitmap<B>,
|
||||
hints: &DecodingHintDictionary,
|
||||
results: &mut Vec<RXingResult>,
|
||||
xOffset: u32,
|
||||
@@ -105,8 +105,8 @@ impl<T: Reader> GenericMultipleBarcodeReader<T> {
|
||||
return;
|
||||
}
|
||||
|
||||
let width = image.getWidth();
|
||||
let height = image.getHeight();
|
||||
let width = image.get_width();
|
||||
let height = image.get_height();
|
||||
let mut minX: f32 = width as f32;
|
||||
let mut minY: f32 = height as f32;
|
||||
let mut maxX: f32 = 0.0;
|
||||
@@ -133,7 +133,7 @@ impl<T: Reader> GenericMultipleBarcodeReader<T> {
|
||||
|
||||
// Decode left of barcode
|
||||
if minX > Self::MIN_DIMENSION_TO_RECUR {
|
||||
self.doDecodeMultiple(
|
||||
self.do_decode_multiple(
|
||||
&mut image.crop(0, 0, minX as usize, height),
|
||||
hints,
|
||||
results,
|
||||
@@ -144,7 +144,7 @@ impl<T: Reader> GenericMultipleBarcodeReader<T> {
|
||||
}
|
||||
// Decode above barcode
|
||||
if minY > Self::MIN_DIMENSION_TO_RECUR {
|
||||
self.doDecodeMultiple(
|
||||
self.do_decode_multiple(
|
||||
&mut image.crop(0, 0, width, minY as usize),
|
||||
hints,
|
||||
results,
|
||||
@@ -155,7 +155,7 @@ impl<T: Reader> GenericMultipleBarcodeReader<T> {
|
||||
}
|
||||
// Decode right of barcode
|
||||
if maxX < (width as f32) - Self::MIN_DIMENSION_TO_RECUR {
|
||||
self.doDecodeMultiple(
|
||||
self.do_decode_multiple(
|
||||
&mut image.crop(maxX as usize, 0, width - maxX as usize, height),
|
||||
hints,
|
||||
results,
|
||||
@@ -166,7 +166,7 @@ impl<T: Reader> GenericMultipleBarcodeReader<T> {
|
||||
}
|
||||
// Decode below barcode
|
||||
if maxY < (height as f32) - Self::MIN_DIMENSION_TO_RECUR {
|
||||
self.doDecodeMultiple(
|
||||
self.do_decode_multiple(
|
||||
&mut image.crop(0, maxY as usize, width, height - maxY as usize),
|
||||
hints,
|
||||
results,
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
use crate::{common::Result, BinaryBitmap, DecodingHintDictionary, RXingResult};
|
||||
use crate::{common::Result, Binarizer, BinaryBitmap, DecodingHintDictionary, RXingResult};
|
||||
|
||||
/**
|
||||
* Implementation of this interface attempt to read several barcodes from one image.
|
||||
@@ -23,11 +23,14 @@ use crate::{common::Result, BinaryBitmap, DecodingHintDictionary, RXingResult};
|
||||
* @author Sean Owen
|
||||
*/
|
||||
pub trait MultipleBarcodeReader {
|
||||
fn decode_multiple(&mut self, image: &mut BinaryBitmap) -> Result<Vec<RXingResult>>;
|
||||
|
||||
fn decode_multiple_with_hints(
|
||||
fn decode_multiple<B: Binarizer>(
|
||||
&mut self,
|
||||
image: &mut BinaryBitmap,
|
||||
image: &mut BinaryBitmap<B>,
|
||||
) -> Result<Vec<RXingResult>>;
|
||||
|
||||
fn decode_multiple_with_hints<B: Binarizer>(
|
||||
&mut self,
|
||||
image: &mut BinaryBitmap<B>,
|
||||
hints: &DecodingHintDictionary,
|
||||
) -> Result<Vec<RXingResult>>;
|
||||
}
|
||||
|
||||
@@ -23,7 +23,8 @@ use crate::{
|
||||
decoder::{self, QRCodeDecoderMetaData},
|
||||
QRCodeReader,
|
||||
},
|
||||
BarcodeFormat, Exceptions, RXingResult, RXingResultMetadataType, RXingResultMetadataValue,
|
||||
BarcodeFormat, Binarizer, Exceptions, RXingResult, RXingResultMetadataType,
|
||||
RXingResultMetadataValue,
|
||||
};
|
||||
|
||||
use super::detector::MultiDetector;
|
||||
@@ -37,20 +38,21 @@ use super::detector::MultiDetector;
|
||||
#[derive(Default)]
|
||||
pub struct QRCodeMultiReader(QRCodeReader);
|
||||
impl MultipleBarcodeReader for QRCodeMultiReader {
|
||||
fn decode_multiple(
|
||||
fn decode_multiple<B: Binarizer>(
|
||||
&mut self,
|
||||
image: &mut crate::BinaryBitmap,
|
||||
) -> Result<Vec<crate::RXingResult>> {
|
||||
image: &mut crate::BinaryBitmap<B>,
|
||||
) -> Result<Vec<RXingResult>> {
|
||||
self.decode_multiple_with_hints(image, &HashMap::new())
|
||||
}
|
||||
|
||||
fn decode_multiple_with_hints(
|
||||
fn decode_multiple_with_hints<B: Binarizer>(
|
||||
&mut self,
|
||||
image: &mut crate::BinaryBitmap,
|
||||
image: &mut crate::BinaryBitmap<B>,
|
||||
hints: &crate::DecodingHintDictionary,
|
||||
) -> Result<Vec<crate::RXingResult>> {
|
||||
) -> Result<Vec<RXingResult>> {
|
||||
let mut results = Vec::new();
|
||||
let detectorRXingResults = MultiDetector::new(image.getBlackMatrix()).detectMulti(hints)?;
|
||||
let detectorRXingResults =
|
||||
MultiDetector::new(image.get_black_matrix()).detectMulti(hints)?;
|
||||
for detectorRXingResult in detectorRXingResults {
|
||||
let mut proc = || -> Result<()> {
|
||||
let decoderRXingResult = decoder::qrcode_decoder::decode_bitmatrix_with_hints(
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,7 +49,7 @@ impl Default for CodaBarReader {
|
||||
}
|
||||
|
||||
impl OneDReader for CodaBarReader {
|
||||
fn decodeRow(
|
||||
fn decode_row(
|
||||
&mut self,
|
||||
rowNumber: u32,
|
||||
row: &crate::common::BitArray,
|
||||
@@ -309,7 +309,7 @@ impl CodaBarReader {
|
||||
self.counterLength = 0;
|
||||
// Start from the first white bit.
|
||||
let mut i = row.getNextUnset(0);
|
||||
let end = row.getSize();
|
||||
let end = row.get_size();
|
||||
if i >= end {
|
||||
return Err(Exceptions::NOT_FOUND);
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ use super::{one_d_reader, OneDReader};
|
||||
pub struct Code128Reader;
|
||||
|
||||
impl OneDReader for Code128Reader {
|
||||
fn decodeRow(
|
||||
fn decode_row(
|
||||
&mut self,
|
||||
rowNumber: u32,
|
||||
row: &crate::common::BitArray,
|
||||
@@ -294,7 +294,7 @@ impl OneDReader for Code128Reader {
|
||||
nextStart = row.getNextUnset(nextStart);
|
||||
if !row.isRange(
|
||||
nextStart,
|
||||
row.getSize().min(nextStart + (nextStart - lastStart) / 2),
|
||||
row.get_size().min(nextStart + (nextStart - lastStart) / 2),
|
||||
false,
|
||||
)? {
|
||||
return Err(Exceptions::NOT_FOUND);
|
||||
@@ -354,7 +354,7 @@ impl OneDReader for Code128Reader {
|
||||
}
|
||||
impl Code128Reader {
|
||||
fn findStartPattern(&self, row: &BitArray) -> Result<[usize; 3]> {
|
||||
let width = row.getSize();
|
||||
let width = row.get_size();
|
||||
let rowOffset = row.getNextSet(0);
|
||||
|
||||
let mut counterPosition = 0;
|
||||
@@ -371,7 +371,7 @@ impl Code128Reader {
|
||||
let mut bestVariance = MAX_AVG_VARIANCE;
|
||||
let mut bestMatch = -1_isize;
|
||||
for startCode in CODE_START_A..=CODE_START_C {
|
||||
let variance = one_d_reader::patternMatchVariance(
|
||||
let variance = one_d_reader::pattern_match_variance(
|
||||
&counters,
|
||||
&CODE_PATTERNS[startCode as usize],
|
||||
MAX_INDIVIDUAL_VARIANCE,
|
||||
@@ -410,13 +410,13 @@ impl Code128Reader {
|
||||
}
|
||||
|
||||
fn decodeCode(&self, row: &BitArray, counters: &mut [u32; 6], rowOffset: usize) -> Result<u8> {
|
||||
one_d_reader::recordPattern(row, rowOffset, counters)?;
|
||||
one_d_reader::record_pattern(row, rowOffset, counters)?;
|
||||
let mut bestVariance = MAX_AVG_VARIANCE; // worst variance we'll accept
|
||||
let mut bestMatch = -1_isize;
|
||||
for d in 0..CODE_PATTERNS.len() {
|
||||
let pattern = &CODE_PATTERNS[d];
|
||||
let variance =
|
||||
one_d_reader::patternMatchVariance(counters, pattern, MAX_INDIVIDUAL_VARIANCE);
|
||||
one_d_reader::pattern_match_variance(counters, pattern, MAX_INDIVIDUAL_VARIANCE);
|
||||
if variance < bestVariance {
|
||||
bestVariance = variance;
|
||||
bestMatch = d as isize;
|
||||
|
||||
@@ -483,18 +483,18 @@ fn encode(toEncode: &str, compact: bool, expectedLoopback: &str) -> Result<BitMa
|
||||
WRITER.encode_with_hints(toEncode, &BarcodeFormat::CODE_128, 0, 0, &hints)?;
|
||||
if !expectedLoopback.is_empty() {
|
||||
let row = encRXingResult.getRow(0);
|
||||
let rtRXingResult = reader.decodeRow(0, &row, &HashMap::new())?;
|
||||
let rtRXingResult = reader.decode_row(0, &row, &HashMap::new())?;
|
||||
let actual = rtRXingResult.getText();
|
||||
assert_eq!(expectedLoopback, actual);
|
||||
}
|
||||
if compact {
|
||||
//check that what is encoded compactly yields the same on loopback as what was encoded fast.
|
||||
let row = encRXingResult.getRow(0);
|
||||
let rtRXingResult = reader.decodeRow(0, &row, &HashMap::new())?;
|
||||
let rtRXingResult = reader.decode_row(0, &row, &HashMap::new())?;
|
||||
let actual = rtRXingResult.getText();
|
||||
let encRXingResultFast = WRITER.encode(toEncode, &BarcodeFormat::CODE_128, 0, 0)?;
|
||||
let row = encRXingResultFast.getRow(0);
|
||||
let rtRXingResult = reader.decodeRow(0, &row, &HashMap::new())?;
|
||||
let rtRXingResult = reader.decode_row(0, &row, &HashMap::new())?;
|
||||
assert_eq!(rtRXingResult.getText(), actual);
|
||||
}
|
||||
Ok(encRXingResult)
|
||||
|
||||
@@ -40,7 +40,7 @@ impl Default for Code39Reader {
|
||||
}
|
||||
}
|
||||
impl OneDReader for Code39Reader {
|
||||
fn decodeRow(
|
||||
fn decode_row(
|
||||
&mut self,
|
||||
rowNumber: u32,
|
||||
row: &crate::common::BitArray,
|
||||
@@ -52,12 +52,12 @@ impl OneDReader for Code39Reader {
|
||||
let start = Self::findAsteriskPattern(row, &mut counters)?;
|
||||
// Read off white space
|
||||
let mut nextStart = row.getNextSet(start[1] as usize);
|
||||
let end = row.getSize();
|
||||
let end = row.get_size();
|
||||
|
||||
let mut decodedChar;
|
||||
let mut lastStart;
|
||||
loop {
|
||||
one_d_reader::recordPattern(row, nextStart, &mut counters)?;
|
||||
one_d_reader::record_pattern(row, nextStart, &mut counters)?;
|
||||
let pattern = Self::toNarrowWidePattern(&counters);
|
||||
if pattern < 0 {
|
||||
return Err(Exceptions::NOT_FOUND);
|
||||
@@ -205,7 +205,7 @@ impl Code39Reader {
|
||||
}
|
||||
|
||||
fn findAsteriskPattern(row: &BitArray, counters: &mut [u32]) -> Result<Vec<u32>> {
|
||||
let width = row.getSize();
|
||||
let width = row.get_size();
|
||||
let rowOffset = row.getNextSet(0);
|
||||
|
||||
let mut counterPosition = 0;
|
||||
@@ -429,7 +429,9 @@ mod code_39_extended_mode_test_case {
|
||||
BitMatrix::parse_strings(encodedRXingResult, "1", "0").expect("bitmatrix parse");
|
||||
// let row = BitArray::with_size(matrix.getWidth() as usize);
|
||||
let row = matrix.getRow(0);
|
||||
let result = sut.decodeRow(0, &row, &HashMap::new()).expect("decode row");
|
||||
let result = sut
|
||||
.decode_row(0, &row, &HashMap::new())
|
||||
.expect("decode row");
|
||||
assert_eq!(expectedRXingResult, result.getText());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ impl Default for Code93Reader {
|
||||
}
|
||||
|
||||
impl OneDReader for Code93Reader {
|
||||
fn decodeRow(
|
||||
fn decode_row(
|
||||
&mut self,
|
||||
rowNumber: u32,
|
||||
row: &crate::common::BitArray,
|
||||
@@ -54,7 +54,7 @@ impl OneDReader for Code93Reader {
|
||||
let start = self.findAsteriskPattern(row)?;
|
||||
// Read off white space
|
||||
let mut nextStart = row.getNextSet(start[1]);
|
||||
let end = row.getSize();
|
||||
let end = row.get_size();
|
||||
|
||||
let mut theCounters = self.counters;
|
||||
theCounters.fill(0);
|
||||
@@ -63,7 +63,7 @@ impl OneDReader for Code93Reader {
|
||||
let mut decodedChar;
|
||||
let mut lastStart;
|
||||
loop {
|
||||
one_d_reader::recordPattern(row, nextStart, &mut theCounters)?;
|
||||
one_d_reader::record_pattern(row, nextStart, &mut theCounters)?;
|
||||
let pattern = Self::toPattern(&theCounters);
|
||||
if pattern < 0 {
|
||||
return Err(Exceptions::NOT_FOUND);
|
||||
@@ -163,7 +163,7 @@ impl Code93Reader {
|
||||
}
|
||||
|
||||
fn findAsteriskPattern(&mut self, row: &BitArray) -> Result<[usize; 2]> {
|
||||
let width = row.getSize();
|
||||
let width = row.get_size();
|
||||
let rowOffset = row.getNextSet(0);
|
||||
|
||||
self.counters.fill(0);
|
||||
@@ -385,7 +385,7 @@ mod Code93ReaderTestCase {
|
||||
// let mut row = BitArray::with_size(matrix.getWidth() as usize);
|
||||
let row = matrix.getRow(0);
|
||||
let result = sut
|
||||
.decodeRow(0, &row, &HashMap::new())
|
||||
.decode_row(0, &row, &HashMap::new())
|
||||
.expect("must decode");
|
||||
assert_eq!(expectedRXingResult, result.getText());
|
||||
}
|
||||
|
||||
@@ -50,7 +50,7 @@ impl UPCEANReader for EAN13Reader {
|
||||
// counters[1] = 0;
|
||||
// counters[2] = 0;
|
||||
// counters[3] = 0;
|
||||
let end = row.getSize();
|
||||
let end = row.get_size();
|
||||
let mut rowOffset = startRange[1];
|
||||
|
||||
let mut lgPatternFound = 0;
|
||||
|
||||
@@ -46,7 +46,7 @@ impl UPCEANReader for EAN8Reader {
|
||||
// counters[1] = 0;
|
||||
// counters[2] = 0;
|
||||
// counters[3] = 0;
|
||||
let end = row.getSize();
|
||||
let end = row.get_size();
|
||||
let mut rowOffset = startRange[1];
|
||||
|
||||
let mut x = 0;
|
||||
|
||||
@@ -104,7 +104,7 @@ impl Default for ITFReader {
|
||||
}
|
||||
|
||||
impl OneDReader for ITFReader {
|
||||
fn decodeRow(
|
||||
fn decode_row(
|
||||
&mut self,
|
||||
rowNumber: u32,
|
||||
row: &crate::common::BitArray,
|
||||
@@ -189,7 +189,7 @@ impl ITFReader {
|
||||
|
||||
while payloadStart < payloadEnd {
|
||||
// Get 10 runs of black/white.
|
||||
one_d_reader::recordPattern(row, payloadStart, &mut counterDigitPair)?;
|
||||
one_d_reader::record_pattern(row, payloadStart, &mut counterDigitPair)?;
|
||||
// Split them into each array
|
||||
for k in 0..5 {
|
||||
let twoK = 2 * k;
|
||||
@@ -275,7 +275,7 @@ impl ITFReader {
|
||||
* @throws NotFoundException Throws exception if no black lines are found in the row
|
||||
*/
|
||||
fn skipWhiteSpace(row: &BitArray) -> Result<usize> {
|
||||
let width = row.getSize();
|
||||
let width = row.get_size();
|
||||
let endStart = row.getNextSet(0);
|
||||
if endStart == width {
|
||||
return Err(Exceptions::NOT_FOUND);
|
||||
@@ -312,8 +312,8 @@ impl ITFReader {
|
||||
// Now recalculate the indices of where the 'endblock' starts & stops to
|
||||
// accommodate the reversed nature of the search
|
||||
let temp = endPattern[0];
|
||||
endPattern[0] = row.getSize() - endPattern[1];
|
||||
endPattern[1] = row.getSize() - temp;
|
||||
endPattern[0] = row.get_size() - endPattern[1];
|
||||
endPattern[1] = row.get_size() - temp;
|
||||
|
||||
Ok(endPattern)
|
||||
};
|
||||
@@ -341,7 +341,7 @@ impl ITFReader {
|
||||
) -> Result<[usize; 2]> {
|
||||
let patternLength = pattern.len();
|
||||
let mut counters = vec![0u32; patternLength]; //new int[patternLength];
|
||||
let width = row.getSize();
|
||||
let width = row.get_size();
|
||||
let mut isWhite = false;
|
||||
|
||||
let mut counterPosition = 0;
|
||||
@@ -352,7 +352,7 @@ impl ITFReader {
|
||||
counters[counterPosition] += 1;
|
||||
} else {
|
||||
if counterPosition == patternLength - 1 {
|
||||
if one_d_reader::patternMatchVariance(
|
||||
if one_d_reader::pattern_match_variance(
|
||||
&counters,
|
||||
pattern,
|
||||
MAX_INDIVIDUAL_VARIANCE,
|
||||
@@ -390,7 +390,7 @@ impl ITFReader {
|
||||
let max = PATTERNS.len();
|
||||
for (i, pattern) in PATTERNS.iter().enumerate().take(max) {
|
||||
let variance =
|
||||
one_d_reader::patternMatchVariance(counters, pattern, MAX_INDIVIDUAL_VARIANCE);
|
||||
one_d_reader::pattern_match_variance(counters, pattern, MAX_INDIVIDUAL_VARIANCE);
|
||||
if variance < bestVariance {
|
||||
bestVariance = variance;
|
||||
bestMatch = i as isize;
|
||||
|
||||
@@ -24,25 +24,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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,11 +15,11 @@
|
||||
*/
|
||||
|
||||
use crate::common::Result;
|
||||
use crate::BarcodeFormat;
|
||||
use crate::DecodeHintValue;
|
||||
use crate::Exceptions;
|
||||
use crate::RXingResult;
|
||||
use crate::Reader;
|
||||
use crate::{BarcodeFormat, Binarizer};
|
||||
|
||||
use super::EAN13Reader;
|
||||
use super::EAN8Reader;
|
||||
@@ -35,47 +35,122 @@ use super::{OneDReader, UPCEANReader};
|
||||
*
|
||||
* @author Sean Owen
|
||||
*/
|
||||
pub struct MultiFormatUPCEANReader(Vec<Box<dyn UPCEANReader>>);
|
||||
pub struct MultiFormatUPCEANReader {
|
||||
possible_formats: HashSet<BarcodeFormat>,
|
||||
}
|
||||
|
||||
impl OneDReader for MultiFormatUPCEANReader {
|
||||
fn decode_row(
|
||||
&mut self,
|
||||
rowNumber: u32,
|
||||
row: &crate::common::BitArray,
|
||||
hints: &DecodingHintDictionary,
|
||||
) -> Result<RXingResult> {
|
||||
let Self {
|
||||
ref possible_formats,
|
||||
} = self;
|
||||
// Compute this location once and reuse it on multiple implementations
|
||||
let start_guard_pattern = STAND_IN.find_start_guard_pattern(row)?;
|
||||
|
||||
if !possible_formats.is_empty() {
|
||||
if possible_formats.contains(&BarcodeFormat::EAN_13) {
|
||||
if let Ok(res) = self.try_decode_function(
|
||||
&EAN13Reader::default(),
|
||||
rowNumber,
|
||||
row,
|
||||
hints,
|
||||
&start_guard_pattern,
|
||||
) {
|
||||
return Ok(res);
|
||||
}
|
||||
} else if possible_formats.contains(&BarcodeFormat::UPC_A) {
|
||||
if let Ok(res) = self.try_decode_function(
|
||||
&UPCAReader::default(),
|
||||
rowNumber,
|
||||
row,
|
||||
hints,
|
||||
&start_guard_pattern,
|
||||
) {
|
||||
return Ok(res);
|
||||
}
|
||||
}
|
||||
if possible_formats.contains(&BarcodeFormat::EAN_8) {
|
||||
if let Ok(res) = self.try_decode_function(
|
||||
&EAN8Reader::default(),
|
||||
rowNumber,
|
||||
row,
|
||||
hints,
|
||||
&start_guard_pattern,
|
||||
) {
|
||||
return Ok(res);
|
||||
}
|
||||
}
|
||||
if possible_formats.contains(&BarcodeFormat::UPC_E) {
|
||||
if let Ok(res) = self.try_decode_function(
|
||||
&UPCEReader::default(),
|
||||
rowNumber,
|
||||
row,
|
||||
hints,
|
||||
&start_guard_pattern,
|
||||
) {
|
||||
return Ok(res);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if let Ok(res) = self.try_decode_function(
|
||||
&EAN13Reader::default(),
|
||||
rowNumber,
|
||||
row,
|
||||
hints,
|
||||
&start_guard_pattern,
|
||||
) {
|
||||
return Ok(res);
|
||||
}
|
||||
if let Ok(res) = self.try_decode_function(
|
||||
&EAN8Reader::default(),
|
||||
rowNumber,
|
||||
row,
|
||||
hints,
|
||||
&start_guard_pattern,
|
||||
) {
|
||||
return Ok(res);
|
||||
}
|
||||
if let Ok(res) = self.try_decode_function(
|
||||
&UPCEReader::default(),
|
||||
rowNumber,
|
||||
row,
|
||||
hints,
|
||||
&start_guard_pattern,
|
||||
) {
|
||||
return Ok(res);
|
||||
}
|
||||
}
|
||||
|
||||
Err(Exceptions::NOT_FOUND)
|
||||
}
|
||||
}
|
||||
|
||||
impl MultiFormatUPCEANReader {
|
||||
pub fn new(hints: &DecodingHintDictionary) -> Self {
|
||||
let mut readers: Vec<Box<dyn UPCEANReader>> = Vec::new();
|
||||
if let Some(DecodeHintValue::PossibleFormats(possibleFormats)) =
|
||||
let possible_formats = if let Some(DecodeHintValue::PossibleFormats(p)) =
|
||||
hints.get(&DecodeHintType::POSSIBLE_FORMATS)
|
||||
{
|
||||
// Collection<BarcodeFormat> possibleFormats = hints == null ? null :
|
||||
// (Collection<BarcodeFormat>) hints.get(DecodeHintType.POSSIBLE_FORMATS);
|
||||
// Collection<UPCEANReader> readers = new ArrayList<>();
|
||||
if possibleFormats.contains(&BarcodeFormat::EAN_13) {
|
||||
readers.push(Box::<EAN13Reader>::default());
|
||||
} else if possibleFormats.contains(&BarcodeFormat::UPC_A) {
|
||||
readers.push(Box::<UPCAReader>::default());
|
||||
}
|
||||
if possibleFormats.contains(&BarcodeFormat::EAN_8) {
|
||||
readers.push(Box::<EAN8Reader>::default());
|
||||
}
|
||||
if possibleFormats.contains(&BarcodeFormat::UPC_E) {
|
||||
readers.push(Box::<UPCEReader>::default());
|
||||
}
|
||||
}
|
||||
if readers.is_empty() {
|
||||
readers.push(Box::<EAN13Reader>::default());
|
||||
// UPC-A is covered by EAN-13
|
||||
readers.push(Box::<EAN8Reader>::default());
|
||||
readers.push(Box::<UPCEReader>::default());
|
||||
}
|
||||
p.clone()
|
||||
} else {
|
||||
HashSet::default()
|
||||
};
|
||||
|
||||
Self(readers)
|
||||
Self { possible_formats }
|
||||
}
|
||||
|
||||
fn try_decode_function(
|
||||
fn try_decode_function<R: UPCEANReader>(
|
||||
&self,
|
||||
reader: &Box<dyn UPCEANReader>,
|
||||
reader: &R,
|
||||
rowNumber: u32,
|
||||
row: &crate::common::BitArray,
|
||||
hints: &crate::DecodingHintDictionary,
|
||||
hints: &DecodingHintDictionary,
|
||||
startGuardPattern: &[usize; 2],
|
||||
) -> Result<crate::RXingResult> {
|
||||
) -> Result<RXingResult> {
|
||||
let result = reader.decodeRowWithGuardRange(rowNumber, row, startGuardPattern, hints)?;
|
||||
// Special case: a 12-digit code encoded in UPC-A is identical to a "0"
|
||||
// followed by those 12 digits encoded as EAN-13. Each will recognize such a code,
|
||||
@@ -117,46 +192,24 @@ impl MultiFormatUPCEANReader {
|
||||
}
|
||||
}
|
||||
|
||||
impl OneDReader for MultiFormatUPCEANReader {
|
||||
fn decodeRow(
|
||||
&mut self,
|
||||
rowNumber: u32,
|
||||
row: &crate::common::BitArray,
|
||||
hints: &crate::DecodingHintDictionary,
|
||||
) -> Result<crate::RXingResult> {
|
||||
// Compute this location once and reuse it on multiple implementations
|
||||
let startGuardPattern = STAND_IN.findStartGuardPattern(row)?;
|
||||
for reader in &self.0 {
|
||||
// for (UPCEANReader reader : readers) {
|
||||
let try_result =
|
||||
self.try_decode_function(reader, rowNumber, row, hints, &startGuardPattern);
|
||||
if try_result.is_ok() {
|
||||
return try_result;
|
||||
}
|
||||
}
|
||||
|
||||
Err(Exceptions::NOT_FOUND)
|
||||
}
|
||||
}
|
||||
|
||||
use crate::DecodeHintType;
|
||||
use crate::DecodingHintDictionary;
|
||||
use crate::RXingResultMetadataType;
|
||||
use crate::RXingResultMetadataValue;
|
||||
use std::collections::HashMap;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
|
||||
impl Reader for MultiFormatUPCEANReader {
|
||||
fn decode(&mut self, image: &mut crate::BinaryBitmap) -> Result<crate::RXingResult> {
|
||||
fn decode<B: Binarizer>(&mut self, image: &mut crate::BinaryBitmap<B>) -> Result<RXingResult> {
|
||||
self.decode_with_hints(image, &HashMap::new())
|
||||
}
|
||||
|
||||
// Note that we don't try rotation without the try harder flag, even if rotation was supported.
|
||||
fn decode_with_hints(
|
||||
fn decode_with_hints<B: Binarizer>(
|
||||
&mut self,
|
||||
image: &mut crate::BinaryBitmap,
|
||||
image: &mut crate::BinaryBitmap<B>,
|
||||
hints: &DecodingHintDictionary,
|
||||
) -> Result<crate::RXingResult> {
|
||||
let first_try = self.doDecode(image, hints);
|
||||
) -> Result<RXingResult> {
|
||||
let first_try = self._do_decode(image, hints);
|
||||
if first_try.is_ok() {
|
||||
return first_try;
|
||||
}
|
||||
@@ -165,16 +218,16 @@ impl Reader for MultiFormatUPCEANReader {
|
||||
hints.get(&DecodeHintType::TRY_HARDER),
|
||||
Some(DecodeHintValue::TryHarder(true))
|
||||
);
|
||||
if tryHarder && image.isRotateSupported() {
|
||||
let mut rotatedImage = image.rotateCounterClockwise();
|
||||
let mut result = self.doDecode(&mut rotatedImage, hints)?;
|
||||
if tryHarder && image.is_rotate_supported() {
|
||||
let mut rotatedImage = image.rotate_counter_clockwise();
|
||||
let mut result = self._do_decode(&mut rotatedImage, hints)?;
|
||||
// Record that we found it rotated 90 degrees CCW / 270 degrees CW
|
||||
let metadata = result.getRXingResultMetadata();
|
||||
let mut orientation = 270;
|
||||
if metadata.contains_key(&RXingResultMetadataType::ORIENTATION) {
|
||||
// But if we found it reversed in doDecode(), add in that result here:
|
||||
orientation = (orientation
|
||||
+ if let Some(crate::RXingResultMetadataValue::Orientation(or)) =
|
||||
+ if let Some(RXingResultMetadataValue::Orientation(or)) =
|
||||
metadata.get(&RXingResultMetadataType::ORIENTATION)
|
||||
{
|
||||
*or
|
||||
@@ -188,7 +241,7 @@ impl Reader for MultiFormatUPCEANReader {
|
||||
RXingResultMetadataValue::Orientation(orientation),
|
||||
);
|
||||
// Update result points
|
||||
let height = rotatedImage.getHeight();
|
||||
let height = rotatedImage.get_height();
|
||||
let total_points = result.getPoints().len();
|
||||
let points = result.getPointsMut();
|
||||
for point in points.iter_mut().take(total_points) {
|
||||
@@ -201,10 +254,4 @@ impl Reader for MultiFormatUPCEANReader {
|
||||
Err(Exceptions::NOT_FOUND)
|
||||
}
|
||||
}
|
||||
|
||||
fn reset(&mut self) {
|
||||
for reader in self.0.iter_mut() {
|
||||
reader.reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,8 +16,8 @@
|
||||
|
||||
use crate::{
|
||||
common::{BitArray, Result},
|
||||
point, BinaryBitmap, DecodeHintType, DecodeHintValue, DecodingHintDictionary, Exceptions,
|
||||
RXingResult, RXingResultMetadataType, RXingResultMetadataValue, Reader,
|
||||
point, Binarizer, BinaryBitmap, DecodeHintType, DecodeHintValue, DecodingHintDictionary,
|
||||
Exceptions, RXingResult, RXingResultMetadataType, RXingResultMetadataValue, Reader,
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -42,45 +42,45 @@ pub trait OneDReader: Reader {
|
||||
* @return The contents of the decoded barcode
|
||||
* @throws NotFoundException Any spontaneous errors which occur
|
||||
*/
|
||||
fn doDecode(
|
||||
fn _do_decode<B: Binarizer>(
|
||||
&mut self,
|
||||
image: &mut BinaryBitmap,
|
||||
image: &mut BinaryBitmap<B>,
|
||||
hints: &DecodingHintDictionary,
|
||||
) -> Result<RXingResult> {
|
||||
let mut hints = hints.clone();
|
||||
let width = image.getWidth();
|
||||
let height = image.getHeight();
|
||||
let width = image.get_width();
|
||||
let height = image.get_height();
|
||||
|
||||
let tryHarder = matches!(
|
||||
let try_harder = matches!(
|
||||
hints.get(&DecodeHintType::TRY_HARDER),
|
||||
Some(DecodeHintValue::TryHarder(true))
|
||||
);
|
||||
let rowStep = 1.max(height >> (if tryHarder { 8 } else { 5 }));
|
||||
let maxLines = if tryHarder {
|
||||
let row_step = 1.max(height >> (if try_harder { 8 } else { 5 }));
|
||||
let max_lines = if try_harder {
|
||||
height // Look at the whole image, not just the center
|
||||
} else {
|
||||
15 // 15 rows spaced 1/32 apart is roughly the middle half of the image
|
||||
};
|
||||
|
||||
let middle = height / 2;
|
||||
for x in 0..maxLines {
|
||||
for x in 0..max_lines {
|
||||
// Scanning from the middle out. Determine which row we're looking at next:
|
||||
let rowStepsAboveOrBelow = (x + 1) / 2;
|
||||
let isAbove = (x & 0x01) == 0; // i.e. is x even?
|
||||
let rowNumber: isize = middle as isize
|
||||
+ rowStep as isize
|
||||
* (if isAbove {
|
||||
rowStepsAboveOrBelow as isize
|
||||
let row_steps_above_or_below = (x + 1) / 2;
|
||||
let is_above = (x & 0x01) == 0; // i.e. is x even?
|
||||
let row_number: isize = middle as isize
|
||||
+ row_step as isize
|
||||
* (if is_above {
|
||||
row_steps_above_or_below as isize
|
||||
} else {
|
||||
-(rowStepsAboveOrBelow as isize)
|
||||
-(row_steps_above_or_below as isize)
|
||||
});
|
||||
if rowNumber < 0 || rowNumber >= height as isize {
|
||||
if row_number < 0 || row_number >= height as isize {
|
||||
// Oops, if we run off the top or bottom, stop
|
||||
break;
|
||||
}
|
||||
|
||||
// Estimate black point for this row and load it:
|
||||
let mut row = if let Ok(res) = image.getBlackRow(rowNumber as usize) {
|
||||
let mut row = if let Ok(res) = image.get_black_row(row_number as usize) {
|
||||
res
|
||||
} else {
|
||||
continue;
|
||||
@@ -104,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(())
|
||||
}
|
||||
|
||||
@@ -33,8 +33,11 @@ pub trait AbstractRSSReaderTrait: OneDReader {
|
||||
|
||||
fn parseFinderValue(counters: &[u32], finderPatterns: &[[u32; 4]]) -> Result<u32> {
|
||||
for (value, pattern) in finderPatterns.iter().enumerate() {
|
||||
if one_d_reader::patternMatchVariance(counters, pattern, Self::MAX_INDIVIDUAL_VARIANCE)
|
||||
< Self::MAX_AVG_VARIANCE
|
||||
if one_d_reader::pattern_match_variance(
|
||||
counters,
|
||||
pattern,
|
||||
Self::MAX_INDIVIDUAL_VARIANCE,
|
||||
) < Self::MAX_AVG_VARIANCE
|
||||
{
|
||||
return Ok(value as u32);
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ pub struct AI01392xDecoder<'a> {
|
||||
impl AI01decoder for AI01392xDecoder<'_> {}
|
||||
impl AbstractExpandedDecoder for AI01392xDecoder<'_> {
|
||||
fn parseInformation(&mut self) -> Result<String> {
|
||||
if self.information.getSize() < Self::HEADER_SIZE + Self::GTIN_SIZE as usize {
|
||||
if self.information.get_size() < Self::HEADER_SIZE + Self::GTIN_SIZE as usize {
|
||||
return Err(crate::Exceptions::NOT_FOUND);
|
||||
}
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ pub struct AI01393xDecoder<'a> {
|
||||
impl AI01decoder for AI01393xDecoder<'_> {}
|
||||
impl AbstractExpandedDecoder for AI01393xDecoder<'_> {
|
||||
fn parseInformation(&mut self) -> Result<String> {
|
||||
if self.information.getSize() < Self::HEADER_SIZE + Self::GTIN_SIZE as usize {
|
||||
if self.information.get_size() < Self::HEADER_SIZE + Self::GTIN_SIZE as usize {
|
||||
return Err(crate::Exceptions::NOT_FOUND);
|
||||
}
|
||||
|
||||
|
||||
@@ -54,7 +54,7 @@ impl AI01weightDecoder for AI013x0x1xDecoder<'_> {
|
||||
impl AI01decoder for AI013x0x1xDecoder<'_> {}
|
||||
impl AbstractExpandedDecoder for AI013x0x1xDecoder<'_> {
|
||||
fn parseInformation(&mut self) -> Result<String> {
|
||||
if self.information.getSize()
|
||||
if self.information.get_size()
|
||||
!= Self::HEADER_SIZE + Self::GTIN_SIZE as usize + Self::WEIGHT_SIZE + Self::DATE_SIZE
|
||||
{
|
||||
return Err(crate::Exceptions::NOT_FOUND);
|
||||
|
||||
@@ -50,7 +50,7 @@ impl AI01weightDecoder for AI013x0xDecoder<'_> {
|
||||
}
|
||||
impl AbstractExpandedDecoder for AI013x0xDecoder<'_> {
|
||||
fn parseInformation(&mut self) -> Result<String> {
|
||||
if self.information.getSize()
|
||||
if self.information.get_size()
|
||||
!= Self::HEADER_SIZE + Self::GTIN_SIZE as usize + Self::WEIGHT_SIZE
|
||||
{
|
||||
return Err(crate::Exceptions::NOT_FOUND);
|
||||
|
||||
@@ -82,8 +82,8 @@ impl<'a> GeneralAppIdDecoder<'_> {
|
||||
fn isStillNumeric(&self, pos: usize) -> bool {
|
||||
// It's numeric if it still has 7 positions
|
||||
// and one of the first 4 bits is "1".
|
||||
if pos + 7 > self.information.getSize() {
|
||||
return pos + 4 <= self.information.getSize();
|
||||
if pos + 7 > self.information.get_size() {
|
||||
return pos + 4 <= self.information.get_size();
|
||||
}
|
||||
|
||||
for i in pos..pos + 3 {
|
||||
@@ -97,17 +97,17 @@ impl<'a> GeneralAppIdDecoder<'_> {
|
||||
}
|
||||
|
||||
fn decodeNumeric(&self, pos: usize) -> Result<DecodedNumeric> {
|
||||
if pos + 7 > self.information.getSize() {
|
||||
if pos + 7 > self.information.get_size() {
|
||||
let numeric = self.extractNumericValueFromBitArray(pos, 4);
|
||||
if numeric == 0 {
|
||||
return DecodedNumeric::new(
|
||||
self.information.getSize(),
|
||||
self.information.get_size(),
|
||||
DecodedNumeric::FNC1,
|
||||
DecodedNumeric::FNC1,
|
||||
);
|
||||
}
|
||||
return DecodedNumeric::new(
|
||||
self.information.getSize(),
|
||||
self.information.get_size(),
|
||||
numeric - 1,
|
||||
DecodedNumeric::FNC1,
|
||||
);
|
||||
@@ -263,10 +263,10 @@ impl<'a> GeneralAppIdDecoder<'_> {
|
||||
self.current.incrementPosition(3);
|
||||
self.current.setNumeric();
|
||||
} else if self.isAlphaTo646ToAlphaLatch(self.current.getPosition()) {
|
||||
if self.current.getPosition() + 5 < self.information.getSize() {
|
||||
if self.current.getPosition() + 5 < self.information.get_size() {
|
||||
self.current.incrementPosition(5);
|
||||
} else {
|
||||
self.current.setPosition(self.information.getSize());
|
||||
self.current.setPosition(self.information.get_size());
|
||||
}
|
||||
|
||||
self.current.setAlpha();
|
||||
@@ -295,10 +295,10 @@ impl<'a> GeneralAppIdDecoder<'_> {
|
||||
self.current.incrementPosition(3);
|
||||
self.current.setNumeric();
|
||||
} else if self.isAlphaTo646ToAlphaLatch(self.current.getPosition()) {
|
||||
if self.current.getPosition() + 5 < self.information.getSize() {
|
||||
if self.current.getPosition() + 5 < self.information.get_size() {
|
||||
self.current.incrementPosition(5);
|
||||
} else {
|
||||
self.current.setPosition(self.information.getSize());
|
||||
self.current.setPosition(self.information.get_size());
|
||||
}
|
||||
|
||||
self.current.setIsoIec646();
|
||||
@@ -308,7 +308,7 @@ impl<'a> GeneralAppIdDecoder<'_> {
|
||||
}
|
||||
|
||||
fn isStillIsoIec646(&self, pos: usize) -> bool {
|
||||
if pos + 5 > self.information.getSize() {
|
||||
if pos + 5 > self.information.get_size() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -317,7 +317,7 @@ impl<'a> GeneralAppIdDecoder<'_> {
|
||||
return true;
|
||||
}
|
||||
|
||||
if pos + 7 > self.information.getSize() {
|
||||
if pos + 7 > self.information.get_size() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -326,7 +326,7 @@ impl<'a> GeneralAppIdDecoder<'_> {
|
||||
return true;
|
||||
}
|
||||
|
||||
if pos + 8 > self.information.getSize() {
|
||||
if pos + 8 > self.information.get_size() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -394,7 +394,7 @@ impl<'a> GeneralAppIdDecoder<'_> {
|
||||
}
|
||||
|
||||
fn isStillAlpha(&self, pos: usize) -> bool {
|
||||
if pos + 5 > self.information.getSize() {
|
||||
if pos + 5 > self.information.get_size() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -404,7 +404,7 @@ impl<'a> GeneralAppIdDecoder<'_> {
|
||||
return true;
|
||||
}
|
||||
|
||||
if pos + 6 > self.information.getSize() {
|
||||
if pos + 6 > self.information.get_size() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -452,12 +452,12 @@ impl<'a> GeneralAppIdDecoder<'_> {
|
||||
}
|
||||
|
||||
fn isAlphaTo646ToAlphaLatch(&self, pos: usize) -> bool {
|
||||
if pos + 1 > self.information.getSize() {
|
||||
if pos + 1 > self.information.get_size() {
|
||||
return false;
|
||||
}
|
||||
|
||||
let mut i = 0;
|
||||
while i < 5 && i + pos < self.information.getSize() {
|
||||
while i < 5 && i + pos < self.information.get_size() {
|
||||
if i == 2 {
|
||||
if !self.information.get(pos + 2) {
|
||||
return false;
|
||||
@@ -474,7 +474,7 @@ impl<'a> GeneralAppIdDecoder<'_> {
|
||||
|
||||
fn isAlphaOr646ToNumericLatch(&self, pos: usize) -> bool {
|
||||
// Next is alphanumeric if there are 3 positions and they are all zeros
|
||||
if pos + 3 > self.information.getSize() {
|
||||
if pos + 3 > self.information.get_size() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -490,12 +490,12 @@ impl<'a> GeneralAppIdDecoder<'_> {
|
||||
fn isNumericToAlphaNumericLatch(&self, pos: usize) -> bool {
|
||||
// Next is alphanumeric if there are 4 positions and they are all zeros, or
|
||||
// if there is a subset of this just before the end of the symbol
|
||||
if pos + 1 > self.information.getSize() {
|
||||
if pos + 1 > self.information.get_size() {
|
||||
return false;
|
||||
}
|
||||
|
||||
let mut i = 0;
|
||||
while i < 4 && i + pos < self.information.getSize() {
|
||||
while i < 4 && i + pos < self.information.get_size() {
|
||||
if self.information.get(pos + i) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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!(
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -29,14 +29,14 @@ use std::collections::HashMap;
|
||||
use crate::{
|
||||
common::{BitArray, Result},
|
||||
oned::{
|
||||
recordPattern, recordPatternInReverse,
|
||||
record_pattern, record_pattern_in_reverse,
|
||||
rss::{
|
||||
rss_utils, AbstractRSSReaderTrait, DataCharacter, DataCharacterTrait, FinderPattern,
|
||||
Pair,
|
||||
},
|
||||
OneDReader,
|
||||
},
|
||||
BarcodeFormat, DecodeHintType, DecodeHintValue, DecodingHintDictionary, Exceptions,
|
||||
BarcodeFormat, Binarizer, DecodeHintType, DecodeHintValue, DecodingHintDictionary, Exceptions,
|
||||
RXingResult, RXingResultMetadataType, RXingResultMetadataValue, Reader,
|
||||
};
|
||||
|
||||
@@ -151,7 +151,7 @@ pub struct RSSExpandedReader {
|
||||
}
|
||||
impl AbstractRSSReaderTrait for RSSExpandedReader {}
|
||||
impl OneDReader for RSSExpandedReader {
|
||||
fn decodeRow(
|
||||
fn decode_row(
|
||||
&mut self,
|
||||
rowNumber: u32,
|
||||
row: &crate::common::BitArray,
|
||||
@@ -173,26 +173,26 @@ impl OneDReader for RSSExpandedReader {
|
||||
}
|
||||
}
|
||||
impl Reader for RSSExpandedReader {
|
||||
fn decode(&mut self, image: &mut crate::BinaryBitmap) -> Result<crate::RXingResult> {
|
||||
fn decode<B: Binarizer>(&mut self, image: &mut crate::BinaryBitmap<B>) -> Result<RXingResult> {
|
||||
self.decode_with_hints(image, &HashMap::new())
|
||||
}
|
||||
|
||||
// Note that we don't try rotation without the try harder flag, even if rotation was supported.
|
||||
fn decode_with_hints(
|
||||
fn decode_with_hints<B: Binarizer>(
|
||||
&mut self,
|
||||
image: &mut crate::BinaryBitmap,
|
||||
image: &mut crate::BinaryBitmap<B>,
|
||||
hints: &DecodingHintDictionary,
|
||||
) -> Result<crate::RXingResult> {
|
||||
if let Ok(res) = self.doDecode(image, hints) {
|
||||
if let Ok(res) = self._do_decode(image, hints) {
|
||||
Ok(res)
|
||||
} else {
|
||||
let tryHarder = matches!(
|
||||
hints.get(&DecodeHintType::TRY_HARDER),
|
||||
Some(DecodeHintValue::TryHarder(true))
|
||||
);
|
||||
if tryHarder && image.isRotateSupported() {
|
||||
let mut rotatedImage = image.rotateCounterClockwise();
|
||||
let mut result = self.doDecode(&mut rotatedImage, hints)?;
|
||||
if tryHarder && image.is_rotate_supported() {
|
||||
let mut rotatedImage = image.rotate_counter_clockwise();
|
||||
let mut result = self._do_decode(&mut rotatedImage, hints)?;
|
||||
// Record that we found it rotated 90 degrees CCW / 270 degrees CW
|
||||
let metadata = result.getRXingResultMetadata();
|
||||
let mut orientation = 270;
|
||||
@@ -213,7 +213,7 @@ impl Reader for RSSExpandedReader {
|
||||
RXingResultMetadataValue::Orientation(orientation),
|
||||
);
|
||||
// Update result points
|
||||
let height = rotatedImage.getHeight();
|
||||
let height = rotatedImage.get_height();
|
||||
|
||||
let total_points = result.getPoints().len();
|
||||
let points = result.getPointsMut();
|
||||
@@ -684,7 +684,7 @@ impl RSSExpandedReader {
|
||||
// counters[2] = 0;
|
||||
// counters[3] = 0;
|
||||
|
||||
let width = row.getSize();
|
||||
let width = row.get_size();
|
||||
|
||||
let mut rowOffset;
|
||||
if forcedOffset >= 0 {
|
||||
@@ -823,9 +823,9 @@ impl RSSExpandedReader {
|
||||
counters.fill(0);
|
||||
|
||||
if leftChar {
|
||||
recordPatternInReverse(row, pattern.getStartEnd()[0], counters)?;
|
||||
record_pattern_in_reverse(row, pattern.getStartEnd()[0], counters)?;
|
||||
} else {
|
||||
recordPattern(row, pattern.getStartEnd()[1], counters)?;
|
||||
record_pattern(row, pattern.getStartEnd()[1], counters)?;
|
||||
// reverse it
|
||||
counters.reverse();
|
||||
// let mut i = 0;
|
||||
|
||||
@@ -39,8 +39,8 @@ fn testDecodingRowByRow() {
|
||||
|
||||
let binaryMap = test_case_util::getBinaryBitmap("1000.png");
|
||||
|
||||
let firstRowNumber = binaryMap.getHeight() / 3;
|
||||
let firstRow = binaryMap.getBlackRow(firstRowNumber).expect("get row");
|
||||
let firstRowNumber = binaryMap.get_height() / 3;
|
||||
let firstRow = binaryMap.get_black_row(firstRowNumber).expect("get row");
|
||||
|
||||
// let tester = ;
|
||||
|
||||
@@ -72,9 +72,9 @@ fn testDecodingRowByRow() {
|
||||
.unwrap()
|
||||
.getStartEndMut()[1] = 0;
|
||||
|
||||
let secondRowNumber = 2 * binaryMap.getHeight() / 3;
|
||||
let secondRowNumber = 2 * binaryMap.get_height() / 3;
|
||||
let mut secondRow = binaryMap
|
||||
.getBlackRow(secondRowNumber)
|
||||
.get_black_row(secondRowNumber)
|
||||
.expect("get row")
|
||||
.into_owned();
|
||||
|
||||
|
||||
@@ -19,8 +19,8 @@ use std::collections::HashMap;
|
||||
use crate::{
|
||||
common::{BitArray, Result},
|
||||
oned::{one_d_reader, OneDReader},
|
||||
point, BarcodeFormat, DecodeHintType, DecodeHintValue, DecodingHintDictionary, Exceptions,
|
||||
RXingResult, RXingResultMetadataType, RXingResultMetadataValue, Reader,
|
||||
point, BarcodeFormat, Binarizer, DecodeHintType, DecodeHintValue, DecodingHintDictionary,
|
||||
Exceptions, RXingResult, RXingResultMetadataType, RXingResultMetadataValue, Reader,
|
||||
};
|
||||
|
||||
use super::{
|
||||
@@ -45,12 +45,12 @@ pub struct RSS14Reader {
|
||||
impl AbstractRSSReaderTrait for RSS14Reader {}
|
||||
|
||||
impl OneDReader for RSS14Reader {
|
||||
fn decodeRow(
|
||||
fn decode_row(
|
||||
&mut self,
|
||||
rowNumber: u32,
|
||||
row: &crate::common::BitArray,
|
||||
hints: &crate::DecodingHintDictionary,
|
||||
) -> Result<crate::RXingResult> {
|
||||
row: &BitArray,
|
||||
hints: &DecodingHintDictionary,
|
||||
) -> Result<RXingResult> {
|
||||
let mut row = row.clone();
|
||||
let leftPair = self.decodePair(&row, false, rowNumber, hints);
|
||||
Self::addOrTally(&mut self.possibleLeftPairs, leftPair);
|
||||
@@ -73,26 +73,26 @@ impl OneDReader for RSS14Reader {
|
||||
}
|
||||
}
|
||||
impl Reader for RSS14Reader {
|
||||
fn decode(&mut self, image: &mut crate::BinaryBitmap) -> Result<crate::RXingResult> {
|
||||
fn decode<B: Binarizer>(&mut self, image: &mut crate::BinaryBitmap<B>) -> Result<RXingResult> {
|
||||
self.decode_with_hints(image, &HashMap::new())
|
||||
}
|
||||
|
||||
// Note that we don't try rotation without the try harder flag, even if rotation was supported.
|
||||
fn decode_with_hints(
|
||||
fn decode_with_hints<B: Binarizer>(
|
||||
&mut self,
|
||||
image: &mut crate::BinaryBitmap,
|
||||
image: &mut crate::BinaryBitmap<B>,
|
||||
hints: &DecodingHintDictionary,
|
||||
) -> Result<crate::RXingResult> {
|
||||
if let Ok(res) = self.doDecode(image, hints) {
|
||||
if let Ok(res) = self._do_decode(image, hints) {
|
||||
Ok(res)
|
||||
} else {
|
||||
let tryHarder = matches!(
|
||||
hints.get(&DecodeHintType::TRY_HARDER),
|
||||
Some(DecodeHintValue::TryHarder(true))
|
||||
);
|
||||
if tryHarder && image.isRotateSupported() {
|
||||
let mut rotatedImage = image.rotateCounterClockwise();
|
||||
let mut result = self.doDecode(&mut rotatedImage, hints)?;
|
||||
if tryHarder && image.is_rotate_supported() {
|
||||
let mut rotatedImage = image.rotate_counter_clockwise();
|
||||
let mut result = self._do_decode(&mut rotatedImage, hints)?;
|
||||
// Record that we found it rotated 90 degrees CCW / 270 degrees CW
|
||||
let metadata = result.getRXingResultMetadata();
|
||||
let mut orientation = 270;
|
||||
@@ -113,7 +113,7 @@ impl Reader for RSS14Reader {
|
||||
RXingResultMetadataValue::Orientation(orientation),
|
||||
);
|
||||
// Update result points
|
||||
let height = rotatedImage.getHeight();
|
||||
let height = rotatedImage.get_height();
|
||||
let total_points = result.getPoints().len();
|
||||
let points = result.getPointsMut();
|
||||
for point in points.iter_mut().take(total_points) {
|
||||
@@ -257,7 +257,7 @@ impl RSS14Reader {
|
||||
let mut center: f32 = (startEnd[0] + startEnd[1] - 1) as f32 / 2.0;
|
||||
if right {
|
||||
// row is actually reversed
|
||||
center = row.getSize() as f32 - 1.0 - center;
|
||||
center = row.get_size() as f32 - 1.0 - center;
|
||||
}
|
||||
cb(point(center, rowNumber as f32));
|
||||
}
|
||||
@@ -287,9 +287,9 @@ impl RSS14Reader {
|
||||
counters.fill(0);
|
||||
|
||||
if outsideChar {
|
||||
one_d_reader::recordPatternInReverse(row, pattern.getStartEnd()[0], counters)?;
|
||||
one_d_reader::record_pattern_in_reverse(row, pattern.getStartEnd()[0], counters)?;
|
||||
} else {
|
||||
one_d_reader::recordPattern(row, pattern.getStartEnd()[1], counters)?;
|
||||
one_d_reader::record_pattern(row, pattern.getStartEnd()[1], counters)?;
|
||||
// reverse it
|
||||
counters.reverse();
|
||||
// let mut i = 0;
|
||||
@@ -379,7 +379,7 @@ impl RSS14Reader {
|
||||
let counters = &mut self.decodeFinderCounters;
|
||||
counters.fill(0);
|
||||
|
||||
let width = row.getSize();
|
||||
let width = row.get_size();
|
||||
let mut isWhite = false;
|
||||
let mut rowOffset = 0;
|
||||
while rowOffset < width {
|
||||
@@ -445,8 +445,8 @@ impl RSS14Reader {
|
||||
let mut end = startEnd[1];
|
||||
if right {
|
||||
// row is actually reversed
|
||||
start = row.getSize() - 1 - start;
|
||||
end = row.getSize() - 1 - end;
|
||||
start = row.get_size() - 1 - start;
|
||||
end = row.get_size() - 1 - end;
|
||||
}
|
||||
|
||||
Ok(FinderPattern::new(
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
use crate::{common::Result, BarcodeFormat, Exceptions, RXingResult, Reader};
|
||||
use crate::{common::Result, BarcodeFormat, Binarizer, Exceptions, RXingResult, Reader};
|
||||
|
||||
use super::{EAN13Reader, OneDReader, UPCEANReader};
|
||||
|
||||
@@ -28,32 +28,50 @@ use super::{EAN13Reader, OneDReader, UPCEANReader};
|
||||
pub struct UPCAReader(EAN13Reader);
|
||||
|
||||
impl Reader for UPCAReader {
|
||||
fn decode(&mut self, image: &mut crate::BinaryBitmap) -> Result<crate::RXingResult> {
|
||||
fn decode<B: Binarizer>(&mut self, image: &mut crate::BinaryBitmap<B>) -> Result<RXingResult> {
|
||||
Self::maybeReturnRXingResult(self.0.decode(image)?)
|
||||
}
|
||||
|
||||
fn decode_with_hints(
|
||||
fn decode_with_hints<B: Binarizer>(
|
||||
&mut self,
|
||||
image: &mut crate::BinaryBitmap,
|
||||
image: &mut crate::BinaryBitmap<B>,
|
||||
hints: &crate::DecodingHintDictionary,
|
||||
) -> Result<crate::RXingResult> {
|
||||
) -> Result<RXingResult> {
|
||||
Self::maybeReturnRXingResult(self.0.decode_with_hints(image, hints)?)
|
||||
}
|
||||
}
|
||||
|
||||
impl OneDReader for UPCAReader {
|
||||
fn decodeRow(
|
||||
fn decode_row(
|
||||
&mut self,
|
||||
rowNumber: u32,
|
||||
row: &crate::common::BitArray,
|
||||
hints: &crate::DecodingHintDictionary,
|
||||
) -> Result<crate::RXingResult> {
|
||||
Self::maybeReturnRXingResult(self.0.decodeRow(rowNumber, row, hints)?)
|
||||
) -> Result<RXingResult> {
|
||||
Self::maybeReturnRXingResult(self.0.decode_row(rowNumber, row, hints)?)
|
||||
}
|
||||
}
|
||||
|
||||
impl UPCEANReader for UPCAReader {
|
||||
fn getBarcodeFormat(&self) -> crate::BarcodeFormat {
|
||||
fn decodeRowWithGuardRange(
|
||||
&self,
|
||||
rowNumber: u32,
|
||||
row: &crate::common::BitArray,
|
||||
startGuardRange: &[usize; 2],
|
||||
hints: &crate::DecodingHintDictionary,
|
||||
) -> Result<RXingResult>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
Self::maybeReturnRXingResult(self.0.decodeRowWithGuardRange(
|
||||
rowNumber,
|
||||
row,
|
||||
startGuardRange,
|
||||
hints,
|
||||
)?)
|
||||
}
|
||||
|
||||
fn getBarcodeFormat(&self) -> BarcodeFormat {
|
||||
BarcodeFormat::UPC_A
|
||||
}
|
||||
|
||||
@@ -65,24 +83,6 @@ impl UPCEANReader for UPCAReader {
|
||||
) -> Result<usize> {
|
||||
self.0.decodeMiddle(row, startRange, resultString)
|
||||
}
|
||||
|
||||
fn decodeRowWithGuardRange(
|
||||
&self,
|
||||
rowNumber: u32,
|
||||
row: &crate::common::BitArray,
|
||||
startGuardRange: &[usize; 2],
|
||||
hints: &crate::DecodingHintDictionary,
|
||||
) -> Result<crate::RXingResult>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
Self::maybeReturnRXingResult(self.0.decodeRowWithGuardRange(
|
||||
rowNumber,
|
||||
row,
|
||||
startGuardRange,
|
||||
hints,
|
||||
)?)
|
||||
}
|
||||
}
|
||||
|
||||
impl UPCAReader {
|
||||
|
||||
@@ -41,7 +41,7 @@ impl UPCEANReader for UPCEReader {
|
||||
) -> Result<usize> {
|
||||
let mut counters = [0_u32; 4];
|
||||
|
||||
let end = row.getSize();
|
||||
let end = row.get_size();
|
||||
let mut rowOffset = startRange[1];
|
||||
|
||||
let mut lgPatternFound = 0;
|
||||
|
||||
@@ -73,7 +73,7 @@ impl UPCEANExtension2Support {
|
||||
let mut counters = self.decodeMiddleCounters;
|
||||
counters.fill(0);
|
||||
|
||||
let end = row.getSize();
|
||||
let end = row.get_size();
|
||||
let mut rowOffset = startRange[1] as usize;
|
||||
|
||||
let mut checkParity = 0;
|
||||
|
||||
@@ -73,7 +73,7 @@ impl UPCEANExtension5Support {
|
||||
resultString: &mut String,
|
||||
) -> Result<u32> {
|
||||
let mut counters = [0_u32; 4];
|
||||
let end = row.getSize();
|
||||
let end = row.get_size();
|
||||
let mut rowOffset = startRange[1];
|
||||
|
||||
let mut lgPatternFound = 0;
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
use crate::{
|
||||
common::{BitArray, Result},
|
||||
point, BarcodeFormat, DecodeHintType, DecodeHintValue, Exceptions, RXingResult,
|
||||
point, BarcodeFormat, Binarizer, DecodeHintType, DecodeHintValue, Exceptions, RXingResult,
|
||||
RXingResultMetadataType, RXingResultMetadataValue, Reader,
|
||||
};
|
||||
|
||||
@@ -101,7 +101,7 @@ pub const L_AND_G_PATTERNS: [[u32; 4]; 20] = {
|
||||
* @author alasdair@google.com (Alasdair Mackintosh)
|
||||
*/
|
||||
pub trait UPCEANReader: OneDReader {
|
||||
fn findStartGuardPattern(&self, row: &BitArray) -> Result<[usize; 2]> {
|
||||
fn find_start_guard_pattern(&self, row: &BitArray) -> Result<[usize; 2]> {
|
||||
let mut foundStart = false;
|
||||
let mut startRange = [0; 2];
|
||||
let mut nextStart = 0;
|
||||
@@ -182,7 +182,7 @@ pub trait UPCEANReader: OneDReader {
|
||||
// spec might want more whitespace, but in practice this is the maximum we can count on.
|
||||
let end = endRange[1];
|
||||
let quietEnd = end + (end - endRange[0]);
|
||||
if quietEnd >= row.getSize() || !row.isRange(end, quietEnd, false)? {
|
||||
if quietEnd >= row.get_size() || !row.isRange(end, quietEnd, false)? {
|
||||
return Err(Exceptions::NOT_FOUND);
|
||||
}
|
||||
|
||||
@@ -382,7 +382,7 @@ pub trait UPCEANReader: OneDReader {
|
||||
pattern: &[u32],
|
||||
counters: &mut [u32],
|
||||
) -> Result<[usize; 2]> {
|
||||
let width = row.getSize();
|
||||
let width = row.get_size();
|
||||
let rowOffset = if whiteFirst {
|
||||
row.getNextUnset(rowOffset)
|
||||
} else {
|
||||
@@ -398,7 +398,7 @@ pub trait UPCEANReader: OneDReader {
|
||||
counters[counterPosition] += 1;
|
||||
} else {
|
||||
if counterPosition == patternLength - 1 {
|
||||
if one_d_reader::patternMatchVariance(
|
||||
if one_d_reader::pattern_match_variance(
|
||||
counters,
|
||||
pattern,
|
||||
MAX_INDIVIDUAL_VARIANCE,
|
||||
@@ -443,13 +443,13 @@ pub trait UPCEANReader: OneDReader {
|
||||
rowOffset: usize,
|
||||
patterns: &[[u32; 4]],
|
||||
) -> Result<usize> {
|
||||
one_d_reader::recordPattern(row, rowOffset, counters)?;
|
||||
one_d_reader::record_pattern(row, rowOffset, counters)?;
|
||||
let mut bestVariance = MAX_AVG_VARIANCE; // worst variance we'll accept
|
||||
let mut bestMatch = -1_isize;
|
||||
let max = patterns.len();
|
||||
for (i, pattern) in patterns.iter().enumerate().take(max) {
|
||||
let variance: f32 =
|
||||
one_d_reader::patternMatchVariance(counters, pattern, MAX_INDIVIDUAL_VARIANCE);
|
||||
one_d_reader::pattern_match_variance(counters, pattern, MAX_INDIVIDUAL_VARIANCE);
|
||||
if variance < bestVariance {
|
||||
bestVariance = variance;
|
||||
bestMatch = i as isize;
|
||||
@@ -503,7 +503,7 @@ impl UPCEANReader for StandInStruct {
|
||||
}
|
||||
}
|
||||
impl OneDReader for StandInStruct {
|
||||
fn decodeRow(
|
||||
fn decode_row(
|
||||
&mut self,
|
||||
_rowNumber: u32,
|
||||
_row: &BitArray,
|
||||
@@ -514,13 +514,13 @@ impl OneDReader for StandInStruct {
|
||||
}
|
||||
|
||||
impl Reader for StandInStruct {
|
||||
fn decode(&mut self, _image: &mut crate::BinaryBitmap) -> Result<RXingResult> {
|
||||
fn decode<B: Binarizer>(&mut self, _image: &mut crate::BinaryBitmap<B>) -> Result<RXingResult> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn decode_with_hints(
|
||||
fn decode_with_hints<B: Binarizer>(
|
||||
&mut self,
|
||||
_image: &mut crate::BinaryBitmap,
|
||||
_image: &mut crate::BinaryBitmap<B>,
|
||||
_hints: &crate::DecodingHintDictionary,
|
||||
) -> Result<RXingResult> {
|
||||
todo!()
|
||||
|
||||
@@ -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)?;
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use crate::{
|
||||
common::Result, multi::MultipleBarcodeReader, BarcodeFormat, BinaryBitmap,
|
||||
common::Result, multi::MultipleBarcodeReader, BarcodeFormat, Binarizer, BinaryBitmap,
|
||||
DecodingHintDictionary, Exceptions, Point, RXingResult, RXingResultMetadataType,
|
||||
RXingResultMetadataValue, Reader,
|
||||
};
|
||||
@@ -43,13 +43,13 @@ impl Reader for PDF417Reader {
|
||||
* @throws NotFoundException if a PDF417 code cannot be found,
|
||||
* @throws FormatException if a PDF417 cannot be decoded
|
||||
*/
|
||||
fn decode(&mut self, image: &mut crate::BinaryBitmap) -> Result<crate::RXingResult> {
|
||||
fn decode<B: Binarizer>(&mut self, image: &mut BinaryBitmap<B>) -> Result<RXingResult> {
|
||||
self.decode_with_hints(image, &HashMap::new())
|
||||
}
|
||||
|
||||
fn decode_with_hints(
|
||||
fn decode_with_hints<B: Binarizer>(
|
||||
&mut self,
|
||||
image: &mut crate::BinaryBitmap,
|
||||
image: &mut BinaryBitmap<B>,
|
||||
hints: &crate::DecodingHintDictionary,
|
||||
) -> Result<crate::RXingResult> {
|
||||
let result = Self::decode(image, hints, false)?;
|
||||
@@ -61,18 +61,18 @@ impl Reader for PDF417Reader {
|
||||
}
|
||||
|
||||
impl MultipleBarcodeReader for PDF417Reader {
|
||||
fn decode_multiple(
|
||||
fn decode_multiple<B: Binarizer>(
|
||||
&mut self,
|
||||
image: &mut crate::BinaryBitmap,
|
||||
) -> Result<Vec<crate::RXingResult>> {
|
||||
image: &mut BinaryBitmap<B>,
|
||||
) -> Result<Vec<RXingResult>> {
|
||||
self.decode_multiple_with_hints(image, &HashMap::new())
|
||||
}
|
||||
|
||||
fn decode_multiple_with_hints(
|
||||
fn decode_multiple_with_hints<B: Binarizer>(
|
||||
&mut self,
|
||||
image: &mut crate::BinaryBitmap,
|
||||
hints: &crate::DecodingHintDictionary,
|
||||
) -> Result<Vec<crate::RXingResult>> {
|
||||
image: &mut BinaryBitmap<B>,
|
||||
hints: &DecodingHintDictionary,
|
||||
) -> Result<Vec<RXingResult>> {
|
||||
Self::decode(image, hints, true)
|
||||
}
|
||||
}
|
||||
@@ -82,8 +82,8 @@ impl PDF417Reader {
|
||||
Self::default()
|
||||
}
|
||||
|
||||
fn decode(
|
||||
image: &mut BinaryBitmap,
|
||||
fn decode<B: Binarizer>(
|
||||
image: &mut BinaryBitmap<B>,
|
||||
hints: &DecodingHintDictionary,
|
||||
multiple: bool,
|
||||
) -> Result<Vec<RXingResult>> {
|
||||
|
||||
@@ -191,8 +191,8 @@ impl PlanarYUVLuminanceSource {
|
||||
}
|
||||
|
||||
pub fn renderThumbnail(&self) -> Vec<u8> {
|
||||
let width = self.getWidth() / THUMBNAIL_SCALE_FACTOR;
|
||||
let height = self.getHeight() / THUMBNAIL_SCALE_FACTOR;
|
||||
let width = self.get_width() / THUMBNAIL_SCALE_FACTOR;
|
||||
let height = self.get_height() / THUMBNAIL_SCALE_FACTOR;
|
||||
let mut pixels = vec![0; width * height];
|
||||
let yuv = &self.yuv_data;
|
||||
let mut input_offset = self.top * self.data_width + self.left;
|
||||
@@ -212,14 +212,14 @@ impl PlanarYUVLuminanceSource {
|
||||
* @return width of image from {@link #renderThumbnail()}
|
||||
*/
|
||||
pub fn getThumbnailWidth(&self) -> usize {
|
||||
self.getWidth() / THUMBNAIL_SCALE_FACTOR
|
||||
self.get_width() / THUMBNAIL_SCALE_FACTOR
|
||||
}
|
||||
|
||||
/**
|
||||
* @return height of image from {@link #renderThumbnail()}
|
||||
*/
|
||||
pub fn getThumbnailHeight(&self) -> usize {
|
||||
self.getHeight() / THUMBNAIL_SCALE_FACTOR
|
||||
self.get_height() / THUMBNAIL_SCALE_FACTOR
|
||||
}
|
||||
|
||||
fn reverseHorizontal(&mut self, width: usize, height: usize) {
|
||||
@@ -237,13 +237,13 @@ impl PlanarYUVLuminanceSource {
|
||||
}
|
||||
|
||||
impl LuminanceSource for PlanarYUVLuminanceSource {
|
||||
fn getRow(&self, y: usize) -> Vec<u8> {
|
||||
if y >= self.getHeight() {
|
||||
fn get_row(&self, y: usize) -> Vec<u8> {
|
||||
if y >= self.get_height() {
|
||||
// //throw new IllegalArgumentException("Requested row is outside the image: " + y);
|
||||
// panic!("Requested row is outside the image: {y}");
|
||||
return Vec::new();
|
||||
}
|
||||
let width = self.getWidth();
|
||||
let width = self.get_width();
|
||||
|
||||
let offset = (y + self.top) * self.data_width + self.left;
|
||||
|
||||
@@ -256,9 +256,9 @@ impl LuminanceSource for PlanarYUVLuminanceSource {
|
||||
row
|
||||
}
|
||||
|
||||
fn getMatrix(&self) -> Vec<u8> {
|
||||
let width = self.getWidth();
|
||||
let height = self.getHeight();
|
||||
fn get_matrix(&self) -> Vec<u8> {
|
||||
let width = self.get_width();
|
||||
let height = self.get_height();
|
||||
|
||||
// If the caller asks for the entire underlying image, save the copy and give them the
|
||||
// original data. The docs specifically warn that result.length must be ignored.
|
||||
@@ -298,26 +298,20 @@ impl LuminanceSource for PlanarYUVLuminanceSource {
|
||||
matrix
|
||||
}
|
||||
|
||||
fn getWidth(&self) -> usize {
|
||||
fn get_width(&self) -> usize {
|
||||
self.width
|
||||
}
|
||||
|
||||
fn getHeight(&self) -> usize {
|
||||
fn get_height(&self) -> usize {
|
||||
self.height
|
||||
}
|
||||
|
||||
fn isCropSupported(&self) -> bool {
|
||||
fn is_crop_supported(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn crop(
|
||||
&self,
|
||||
left: usize,
|
||||
top: usize,
|
||||
width: usize,
|
||||
height: usize,
|
||||
) -> Result<Box<dyn LuminanceSource>> {
|
||||
match PlanarYUVLuminanceSource::new_with_all(
|
||||
fn crop(&self, left: usize, top: usize, width: usize, height: usize) -> Result<Self> {
|
||||
PlanarYUVLuminanceSource::new_with_all(
|
||||
self.yuv_data.clone(),
|
||||
self.data_width,
|
||||
self.data_height,
|
||||
@@ -327,13 +321,11 @@ impl LuminanceSource for PlanarYUVLuminanceSource {
|
||||
height,
|
||||
false,
|
||||
self.invert,
|
||||
) {
|
||||
Ok(new) => Ok(Box::new(new)),
|
||||
Err(_err) => Err(Exceptions::UNSUPPORTED_OPERATION),
|
||||
}
|
||||
)
|
||||
.map_err(|_| Exceptions::UNSUPPORTED_OPERATION)
|
||||
}
|
||||
|
||||
fn isRotateSupported(&self) -> bool {
|
||||
fn is_rotate_supported(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
|
||||
@@ -39,43 +39,43 @@ fn testAppendBit() {
|
||||
assert_eq!(0, v.getSizeInBytes());
|
||||
// 1
|
||||
v.appendBit(true);
|
||||
assert_eq!(1, v.getSize());
|
||||
assert_eq!(1, v.get_size());
|
||||
assert_eq!(0x80000000, getUnsignedInt(&v));
|
||||
// 10
|
||||
v.appendBit(false);
|
||||
assert_eq!(2, v.getSize());
|
||||
assert_eq!(2, v.get_size());
|
||||
assert_eq!(0x80000000, getUnsignedInt(&v));
|
||||
// 101
|
||||
v.appendBit(true);
|
||||
assert_eq!(3, v.getSize());
|
||||
assert_eq!(3, v.get_size());
|
||||
assert_eq!(0xa0000000, getUnsignedInt(&v));
|
||||
// 1010
|
||||
v.appendBit(false);
|
||||
assert_eq!(4, v.getSize());
|
||||
assert_eq!(4, v.get_size());
|
||||
assert_eq!(0xa0000000, getUnsignedInt(&v));
|
||||
// 10101
|
||||
v.appendBit(true);
|
||||
assert_eq!(5, v.getSize());
|
||||
assert_eq!(5, v.get_size());
|
||||
assert_eq!(0xa8000000, getUnsignedInt(&v));
|
||||
// 101010
|
||||
v.appendBit(false);
|
||||
assert_eq!(6, v.getSize());
|
||||
assert_eq!(6, v.get_size());
|
||||
assert_eq!(0xa8000000, getUnsignedInt(&v));
|
||||
// 1010101
|
||||
v.appendBit(true);
|
||||
assert_eq!(7, v.getSize());
|
||||
assert_eq!(7, v.get_size());
|
||||
assert_eq!(0xaa000000, getUnsignedInt(&v));
|
||||
// 10101010
|
||||
v.appendBit(false);
|
||||
assert_eq!(8, v.getSize());
|
||||
assert_eq!(8, v.get_size());
|
||||
assert_eq!(0xaa000000, getUnsignedInt(&v));
|
||||
// 10101010 1
|
||||
v.appendBit(true);
|
||||
assert_eq!(9, v.getSize());
|
||||
assert_eq!(9, v.get_size());
|
||||
assert_eq!(0xaa800000, getUnsignedInt(&v));
|
||||
// 10101010 10
|
||||
v.appendBit(false);
|
||||
assert_eq!(10, v.getSize());
|
||||
assert_eq!(10, v.get_size());
|
||||
assert_eq!(0xaa800000, getUnsignedInt(&v));
|
||||
}
|
||||
|
||||
@@ -83,15 +83,15 @@ fn testAppendBit() {
|
||||
fn testAppendBits() {
|
||||
let mut v = BitArray::new();
|
||||
v.appendBits(0x1, 1).expect("append");
|
||||
assert_eq!(1, v.getSize());
|
||||
assert_eq!(1, v.get_size());
|
||||
assert_eq!(0x80000000, getUnsignedInt(&v));
|
||||
let mut v = BitArray::new();
|
||||
v.appendBits(0xff, 8).expect("append");
|
||||
assert_eq!(8, v.getSize());
|
||||
assert_eq!(8, v.get_size());
|
||||
assert_eq!(0xff000000, getUnsignedInt(&v));
|
||||
let mut v = BitArray::new();
|
||||
v.appendBits(0xff7, 12).expect("append");
|
||||
assert_eq!(12, v.getSize());
|
||||
assert_eq!(12, v.get_size());
|
||||
assert_eq!(0xff700000, getUnsignedInt(&v));
|
||||
}
|
||||
|
||||
|
||||
@@ -174,11 +174,11 @@ pub fn embedTypeInfo(
|
||||
for (i, coordinates) in TYPE_INFO_COORDINATES
|
||||
.iter()
|
||||
.enumerate()
|
||||
.take(typeInfoBits.getSize())
|
||||
.take(typeInfoBits.get_size())
|
||||
{
|
||||
// Place bits in LSB to MSB order. LSB (least significant bit) is the last value in
|
||||
// "typeInfoBits".
|
||||
let bit = typeInfoBits.get(typeInfoBits.getSize() - 1 - i);
|
||||
let bit = typeInfoBits.get(typeInfoBits.get_size() - 1 - i);
|
||||
|
||||
// Type info bits at the left top corner. See 8.9 of JISX0510:2004 (p.46).
|
||||
// let coordinates = TYPE_INFO_COORDINATES[i];
|
||||
@@ -249,7 +249,7 @@ pub fn embedDataBits(dataBits: &BitArray, maskPattern: i32, matrix: &mut ByteMat
|
||||
continue;
|
||||
}
|
||||
let mut bit;
|
||||
if bitIndex < dataBits.getSize() {
|
||||
if bitIndex < dataBits.get_size() {
|
||||
bit = dataBits.get(bitIndex);
|
||||
bitIndex += 1;
|
||||
} else {
|
||||
@@ -273,11 +273,11 @@ pub fn embedDataBits(dataBits: &BitArray, maskPattern: i32, matrix: &mut ByteMat
|
||||
x -= 2; // Move to the left.
|
||||
}
|
||||
// All bits should be consumed.
|
||||
if bitIndex != dataBits.getSize() {
|
||||
if bitIndex != dataBits.get_size() {
|
||||
return Err(Exceptions::writer_with(format!(
|
||||
"Not all bits consumed: {}/{}",
|
||||
bitIndex,
|
||||
dataBits.getSize()
|
||||
dataBits.get_size()
|
||||
)));
|
||||
}
|
||||
Ok(())
|
||||
@@ -355,11 +355,11 @@ pub fn makeTypeInfoBits(
|
||||
maskBits.appendBits(TYPE_INFO_MASK_PATTERN, 15)?;
|
||||
bits.xor(&maskBits)?;
|
||||
|
||||
if bits.getSize() != 15 {
|
||||
if bits.get_size() != 15 {
|
||||
// Just in case.
|
||||
return Err(Exceptions::writer_with(format!(
|
||||
"should not happen but we got: {}",
|
||||
bits.getSize()
|
||||
bits.get_size()
|
||||
)));
|
||||
}
|
||||
Ok(())
|
||||
@@ -372,11 +372,11 @@ pub fn makeVersionInfoBits(version: &Version, bits: &mut BitArray) -> Result<()>
|
||||
let bchCode = calculateBCHCode(version.getVersionNumber(), VERSION_INFO_POLY)?;
|
||||
bits.appendBits(bchCode, 12)?;
|
||||
|
||||
if bits.getSize() != 18 {
|
||||
if bits.get_size() != 18 {
|
||||
// Just in case.
|
||||
return Err(Exceptions::writer_with(format!(
|
||||
"should not happen but we got: {}",
|
||||
bits.getSize()
|
||||
bits.get_size()
|
||||
)));
|
||||
}
|
||||
Ok(())
|
||||
|
||||
@@ -286,7 +286,7 @@ fn calculateBitsNeeded(
|
||||
data_bits: &BitArray,
|
||||
version: VersionRef,
|
||||
) -> u32 {
|
||||
(header_bits.getSize() + mode.getCharacterCountBits(version) as usize + data_bits.getSize())
|
||||
(header_bits.get_size() + mode.getCharacterCountBits(version) as usize + data_bits.get_size())
|
||||
as u32
|
||||
}
|
||||
|
||||
@@ -413,21 +413,21 @@ pub fn willFit(numInputBits: u32, version: VersionRef, ecLevel: &ErrorCorrection
|
||||
*/
|
||||
pub fn terminateBits(num_data_bytes: u32, bits: &mut BitArray) -> Result<()> {
|
||||
let capacity = num_data_bytes * 8;
|
||||
if bits.getSize() > capacity as usize {
|
||||
if bits.get_size() > capacity as usize {
|
||||
return Err(Exceptions::writer_with(format!(
|
||||
"data bits cannot fit in the QR Code{capacity} > "
|
||||
)));
|
||||
}
|
||||
// Append Mode.TERMINATE if there is enough space (value is 0000)
|
||||
for _i in 0..4 {
|
||||
if bits.getSize() >= capacity as usize {
|
||||
if bits.get_size() >= capacity as usize {
|
||||
break;
|
||||
}
|
||||
bits.appendBit(false);
|
||||
}
|
||||
// Append termination bits. See 8.4.8 of JISX0510:2004 (p.24) for details.
|
||||
// If the last byte isn't 8-bit aligned, we'll add padding bits.
|
||||
let num_bits_in_last_byte = bits.getSize() & 0x07;
|
||||
let num_bits_in_last_byte = bits.get_size() & 0x07;
|
||||
if num_bits_in_last_byte > 0 {
|
||||
for _i in num_bits_in_last_byte..8 {
|
||||
bits.appendBit(false);
|
||||
@@ -441,7 +441,7 @@ pub fn terminateBits(num_data_bytes: u32, bits: &mut BitArray) -> Result<()> {
|
||||
}
|
||||
bits.appendBits(if (i & 0x01) == 0 { 0xEC } else { 0x11 }, 8)?;
|
||||
}
|
||||
if bits.getSize() != capacity as usize {
|
||||
if bits.get_size() != capacity as usize {
|
||||
return Err(Exceptions::writer_with("Bits size does not equal capacity"));
|
||||
}
|
||||
Ok(())
|
||||
|
||||
@@ -18,7 +18,7 @@ use std::collections::HashMap;
|
||||
|
||||
use crate::{
|
||||
common::{BitMatrix, DecoderRXingResult, DetectorRXingResult, Result},
|
||||
BarcodeFormat, DecodeHintType, DecodeHintValue, Exceptions, Point, RXingResult,
|
||||
BarcodeFormat, Binarizer, DecodeHintType, DecodeHintValue, Exceptions, Point, RXingResult,
|
||||
RXingResultMetadataType, RXingResultMetadataValue, Reader,
|
||||
};
|
||||
|
||||
@@ -48,27 +48,27 @@ impl Reader for QRCodeReader {
|
||||
* @throws FormatException if a QR code cannot be decoded
|
||||
* @throws ChecksumException if error correction fails
|
||||
*/
|
||||
fn decode(&mut self, image: &mut crate::BinaryBitmap) -> Result<crate::RXingResult> {
|
||||
fn decode<B: Binarizer>(&mut self, image: &mut crate::BinaryBitmap<B>) -> Result<RXingResult> {
|
||||
self.decode_with_hints(image, &HashMap::new())
|
||||
}
|
||||
|
||||
fn decode_with_hints(
|
||||
fn decode_with_hints<B: Binarizer>(
|
||||
&mut self,
|
||||
image: &mut crate::BinaryBitmap,
|
||||
image: &mut crate::BinaryBitmap<B>,
|
||||
hints: &crate::DecodingHintDictionary,
|
||||
) -> Result<crate::RXingResult> {
|
||||
) -> Result<RXingResult> {
|
||||
let decoderRXingResult: DecoderRXingResult;
|
||||
let mut points: Vec<Point>;
|
||||
if matches!(
|
||||
hints.get(&DecodeHintType::PURE_BARCODE),
|
||||
Some(DecodeHintValue::PureBarcode(true))
|
||||
) {
|
||||
let bits = Self::extractPureBits(image.getBlackMatrix())?;
|
||||
let bits = Self::extractPureBits(image.get_black_matrix())?;
|
||||
decoderRXingResult = qrcode_decoder::decode_bitmatrix_with_hints(&bits, hints)?;
|
||||
points = Vec::new();
|
||||
} else {
|
||||
let detectorRXingResult =
|
||||
Detector::new(image.getBlackMatrix()).detect_with_hints(hints)?;
|
||||
Detector::new(image.get_black_matrix()).detect_with_hints(hints)?;
|
||||
decoderRXingResult =
|
||||
qrcode_decoder::decode_bitmatrix_with_hints(detectorRXingResult.getBits(), hints)?;
|
||||
points = detectorRXingResult.getPoints().to_vec();
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
//package com.google.zxing;
|
||||
|
||||
use crate::{common::Result, BinaryBitmap, DecodingHintDictionary, RXingResult};
|
||||
use crate::{common::Result, Binarizer, BinaryBitmap, DecodingHintDictionary, RXingResult};
|
||||
|
||||
/**
|
||||
* Implementations of this interface can decode an image of a barcode in some format into
|
||||
@@ -40,7 +40,7 @@ pub trait Reader {
|
||||
* @throws ChecksumException if a potential barcode is found but does not pass its checksum
|
||||
* @throws FormatException if a potential barcode is found but format is invalid
|
||||
*/
|
||||
fn decode(&mut self, image: &mut BinaryBitmap) -> Result<RXingResult>;
|
||||
fn decode<B: Binarizer>(&mut self, image: &mut BinaryBitmap<B>) -> Result<RXingResult>;
|
||||
|
||||
/**
|
||||
* Locates and decodes a barcode in some format within an image. This method also accepts
|
||||
@@ -56,9 +56,9 @@ pub trait Reader {
|
||||
* @throws ChecksumException if a potential barcode is found but does not pass its checksum
|
||||
* @throws FormatException if a potential barcode is found but format is invalid
|
||||
*/
|
||||
fn decode_with_hints(
|
||||
fn decode_with_hints<B: Binarizer>(
|
||||
&mut self,
|
||||
image: &mut BinaryBitmap,
|
||||
image: &mut BinaryBitmap<B>,
|
||||
hints: &DecodingHintDictionary,
|
||||
) -> Result<RXingResult>;
|
||||
|
||||
|
||||
@@ -40,11 +40,11 @@ pub struct RGBLuminanceSource {
|
||||
|
||||
impl LuminanceSource for RGBLuminanceSource {
|
||||
/// gets a row, returns an empty row if we are out of bounds.
|
||||
fn getRow(&self, y: usize) -> Vec<u8> {
|
||||
if y >= self.getHeight() {
|
||||
fn get_row(&self, y: usize) -> Vec<u8> {
|
||||
if y >= self.get_height() {
|
||||
return Vec::new();
|
||||
}
|
||||
let width = self.getWidth();
|
||||
let width = self.get_width();
|
||||
|
||||
let offset = (y + self.top) * self.dataWidth + self.left;
|
||||
|
||||
@@ -58,9 +58,9 @@ impl LuminanceSource for RGBLuminanceSource {
|
||||
row
|
||||
}
|
||||
|
||||
fn getMatrix(&self) -> Vec<u8> {
|
||||
let width = self.getWidth();
|
||||
let height = self.getHeight();
|
||||
fn get_matrix(&self) -> Vec<u8> {
|
||||
let width = self.get_width();
|
||||
let height = self.get_height();
|
||||
|
||||
// If the caller asks for the entire underlying image, save the copy and give them the
|
||||
// original data. The docs specifically warn that result.length must be ignored.
|
||||
@@ -99,26 +99,20 @@ impl LuminanceSource for RGBLuminanceSource {
|
||||
matrix
|
||||
}
|
||||
|
||||
fn getWidth(&self) -> usize {
|
||||
fn get_width(&self) -> usize {
|
||||
self.width
|
||||
}
|
||||
|
||||
fn getHeight(&self) -> usize {
|
||||
fn get_height(&self) -> usize {
|
||||
self.height
|
||||
}
|
||||
|
||||
fn isCropSupported(&self) -> bool {
|
||||
fn is_crop_supported(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn crop(
|
||||
&self,
|
||||
left: usize,
|
||||
top: usize,
|
||||
width: usize,
|
||||
height: usize,
|
||||
) -> Result<Box<dyn LuminanceSource>> {
|
||||
match RGBLuminanceSource::new_complex(
|
||||
fn crop(&self, left: usize, top: usize, width: usize, height: usize) -> Result<Self> {
|
||||
RGBLuminanceSource::new_complex(
|
||||
&self.luminances,
|
||||
self.dataWidth,
|
||||
self.dataHeight,
|
||||
@@ -126,10 +120,8 @@ impl LuminanceSource for RGBLuminanceSource {
|
||||
self.top + top,
|
||||
width,
|
||||
height,
|
||||
) {
|
||||
Ok(crop) => Ok(Box::new(crop)),
|
||||
Err(_error) => Err(Exceptions::UNSUPPORTED_OPERATION),
|
||||
}
|
||||
)
|
||||
.map_err(|_| Exceptions::UNSUPPORTED_OPERATION)
|
||||
}
|
||||
|
||||
fn invert(&mut self) {
|
||||
|
||||
@@ -34,11 +34,11 @@ const SRC_DATA: [u32; 9] = [
|
||||
fn testCrop() {
|
||||
let SOURCE = RGBLuminanceSource::new_with_width_height_pixels(3, 3, SRC_DATA.as_ref());
|
||||
|
||||
assert!(SOURCE.isCropSupported());
|
||||
assert!(SOURCE.is_crop_supported());
|
||||
let cropped = SOURCE.crop(1, 1, 1, 1).unwrap();
|
||||
assert_eq!(1, cropped.getHeight());
|
||||
assert_eq!(1, cropped.getWidth());
|
||||
assert_eq!(vec![0x7F], cropped.getRow(0));
|
||||
assert_eq!(1, cropped.get_height());
|
||||
assert_eq!(1, cropped.get_width());
|
||||
assert_eq!(vec![0x7F], cropped.get_row(0));
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -47,22 +47,22 @@ fn testMatrix() {
|
||||
|
||||
assert_eq!(
|
||||
vec![0x00, 0x7F, 0xFF, 0x3F, 0x7F, 0x3F, 0x3F, 0x7F, 0x3F],
|
||||
SOURCE.getMatrix()
|
||||
SOURCE.get_matrix()
|
||||
);
|
||||
let croppedFullWidth = SOURCE.crop(0, 1, 3, 2).unwrap();
|
||||
assert_eq!(
|
||||
vec![0x3F, 0x7F, 0x3F, 0x3F, 0x7F, 0x3F],
|
||||
croppedFullWidth.getMatrix()
|
||||
croppedFullWidth.get_matrix()
|
||||
);
|
||||
let croppedCorner = SOURCE.crop(1, 1, 2, 2).unwrap();
|
||||
assert_eq!(vec![0x7F, 0x3F, 0x7F, 0x3F], croppedCorner.getMatrix());
|
||||
assert_eq!(vec![0x7F, 0x3F, 0x7F, 0x3F], croppedCorner.get_matrix());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn testGetRow() {
|
||||
let SOURCE = RGBLuminanceSource::new_with_width_height_pixels(3, 3, SRC_DATA.as_ref());
|
||||
|
||||
assert_eq!(vec![0x3F, 0x7F, 0x3F], SOURCE.getRow(2));
|
||||
assert_eq!(vec![0x3F, 0x7F, 0x3F], SOURCE.get_row(2));
|
||||
}
|
||||
|
||||
// #[test]
|
||||
|
||||
@@ -6,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()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user