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