mirror of
https://github.com/starovoid/rxing.git
synced 2026-07-26 04:12:34 +00:00
wip: inop dx_film_edge port and filtered reader
This commit is contained in:
@@ -119,6 +119,7 @@ impl Display for BarcodeFormat {
|
|||||||
BarcodeFormat::UPC_A => "upc a",
|
BarcodeFormat::UPC_A => "upc a",
|
||||||
BarcodeFormat::UPC_E => "upc e",
|
BarcodeFormat::UPC_E => "upc e",
|
||||||
BarcodeFormat::UPC_EAN_EXTENSION => "upc/ean extension",
|
BarcodeFormat::UPC_EAN_EXTENSION => "upc/ean extension",
|
||||||
|
BarcodeFormat::DXFilmEdge => "DXFilmEdge",
|
||||||
_ => "unsuported",
|
_ => "unsuported",
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@@ -166,6 +167,7 @@ impl From<&str> for BarcodeFormat {
|
|||||||
"upc e" | "upc_e" | "upce" => BarcodeFormat::UPC_E,
|
"upc e" | "upc_e" | "upce" => BarcodeFormat::UPC_E,
|
||||||
"upc ean extension" | "upc extension" | "ean extension" | "upc/ean extension"
|
"upc ean extension" | "upc extension" | "ean extension" | "upc/ean extension"
|
||||||
| "upc_ean_extension" => BarcodeFormat::UPC_EAN_EXTENSION,
|
| "upc_ean_extension" => BarcodeFormat::UPC_EAN_EXTENSION,
|
||||||
|
"DXFilmEdge" | "dxfilmedge" | "dx film edge" => BarcodeFormat::DXFilmEdge,
|
||||||
_ => BarcodeFormat::UNSUPORTED_FORMAT,
|
_ => BarcodeFormat::UNSUPORTED_FORMAT,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ use crate::{
|
|||||||
|
|
||||||
pub struct BinaryBitmap<B: Binarizer> {
|
pub struct BinaryBitmap<B: Binarizer> {
|
||||||
binarizer: B,
|
binarizer: B,
|
||||||
matrix: Option<BitMatrix>,
|
pub(crate) matrix: Option<BitMatrix>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<B: Binarizer> BinaryBitmap<B> {
|
impl<B: Binarizer> BinaryBitmap<B> {
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
use image::{DynamicImage, ImageBuffer, Luma};
|
use image::{DynamicImage, GenericImageView, ImageBuffer, Luma, Pixel};
|
||||||
use imageproc::geometric_transformations::rotate_about_center;
|
use imageproc::geometric_transformations::rotate_about_center;
|
||||||
|
|
||||||
use crate::common::Result;
|
use crate::common::Result;
|
||||||
@@ -108,6 +108,33 @@ impl LuminanceSource for BufferedImageLuminanceSource {
|
|||||||
pixels
|
pixels
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_column(&self, x: usize) -> Vec<u8> {
|
||||||
|
let width = self.get_height(); // - self.left as usize;
|
||||||
|
|
||||||
|
let pixels: Vec<u8> = || -> Option<Vec<u8>> {
|
||||||
|
Some(
|
||||||
|
self.image
|
||||||
|
.as_luma8()?
|
||||||
|
.rows()
|
||||||
|
.skip(self.top as usize)
|
||||||
|
.fold(Vec::default(), |mut acc, e| {
|
||||||
|
acc.push(
|
||||||
|
e.into_iter()
|
||||||
|
.nth(self.left as usize + x)
|
||||||
|
.unwrap_or(&Luma([0_u8])),
|
||||||
|
);
|
||||||
|
acc
|
||||||
|
})
|
||||||
|
.iter()
|
||||||
|
.map(|&p| p.0[0])
|
||||||
|
.collect(),
|
||||||
|
)
|
||||||
|
}()
|
||||||
|
.unwrap_or_default();
|
||||||
|
|
||||||
|
pixels
|
||||||
|
}
|
||||||
|
|
||||||
fn get_matrix(&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
|
||||||
{
|
{
|
||||||
@@ -201,4 +228,8 @@ impl LuminanceSource for BufferedImageLuminanceSource {
|
|||||||
top: 0,
|
top: 0,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_luma8_point(&self, x: usize, y: usize) -> u8 {
|
||||||
|
self.image.get_pixel(x as u32, y as u32).to_luma().0[0]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -217,7 +217,7 @@ impl<'a> PatternView<'a> {
|
|||||||
pub fn isValidWithN(&self, n: usize) -> bool {
|
pub fn isValidWithN(&self, n: usize) -> bool {
|
||||||
!self.data.0.is_empty()
|
!self.data.0.is_empty()
|
||||||
&& self.start <= self.current + self.start
|
&& self.start <= self.current + self.start
|
||||||
&& self.current + n <= (self.data.0.len())
|
&& self.current + n < (self.data.0.len())
|
||||||
/*return _data && _data >= _base && _data + n <= _end;*/
|
/*return _data && _data >= _base && _data + n <= _end;*/
|
||||||
}
|
}
|
||||||
pub fn isValid(&self) -> bool {
|
pub fn isValid(&self) -> bool {
|
||||||
@@ -271,7 +271,10 @@ impl<'a> PatternView<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn extend(&mut self) {
|
pub fn extend(&mut self) {
|
||||||
self.count = std::cmp::max(0, self.data.len() - (self.current + self.start))
|
self.count = std::cmp::max(
|
||||||
|
0,
|
||||||
|
self.data.len() as isize - (self.current + self.start) as isize,
|
||||||
|
) as usize
|
||||||
}
|
}
|
||||||
|
|
||||||
fn try_get_index(&self, index: isize) -> Option<PatternType> {
|
fn try_get_index(&self, index: isize) -> Option<PatternType> {
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ use once_cell::unsync::OnceCell;
|
|||||||
use crate::common::Result;
|
use crate::common::Result;
|
||||||
use crate::{Binarizer, Exceptions, LuminanceSource};
|
use crate::{Binarizer, Exceptions, LuminanceSource};
|
||||||
|
|
||||||
use super::{BitArray, BitMatrix};
|
use super::{BitArray, BitMatrix, LineOrientation};
|
||||||
|
|
||||||
const LUMINANCE_BITS: usize = 5;
|
const LUMINANCE_BITS: usize = 5;
|
||||||
const LUMINANCE_SHIFT: usize = 8 - LUMINANCE_BITS;
|
const LUMINANCE_SHIFT: usize = 8 - LUMINANCE_BITS;
|
||||||
@@ -107,8 +107,55 @@ impl<LS: LuminanceSource> Binarizer for GlobalHistogramBinarizer<LS> {
|
|||||||
Ok(Cow::Borrowed(row))
|
Ok(Cow::Borrowed(row))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_black_line(&self, l: usize, lt: super::LineOrientation) -> Result<Cow<BitArray>> {
|
fn get_black_line(&self, l: usize, lt: LineOrientation) -> Result<Cow<BitArray>> {
|
||||||
unimplemented!()
|
if lt == LineOrientation::Row {
|
||||||
|
self.get_black_row(l)
|
||||||
|
} else {
|
||||||
|
let col = self.black_column_cache[l].get_or_try_init(|| {
|
||||||
|
let source = self.get_luminance_source();
|
||||||
|
let width = source.get_height();
|
||||||
|
let mut col = BitArray::with_size(width);
|
||||||
|
|
||||||
|
// self.initArrays(width);
|
||||||
|
let localLuminances = source.get_column(l);
|
||||||
|
let mut localBuckets = [0; LUMINANCE_BUCKETS]; //self.buckets.clone();
|
||||||
|
for x in 0..width {
|
||||||
|
// for (int x = 0; x < width; x++) {
|
||||||
|
localBuckets[((localLuminances[x]) >> LUMINANCE_SHIFT) as usize] += 1;
|
||||||
|
}
|
||||||
|
let blackPoint = Self::estimateBlackPoint(&localBuckets)?;
|
||||||
|
|
||||||
|
if width < 3 {
|
||||||
|
// Special case for very small images
|
||||||
|
for (x, lum) in localLuminances.iter().enumerate().take(width) {
|
||||||
|
// for x in 0..width {
|
||||||
|
// for (int x = 0; x < width; x++) {
|
||||||
|
if (*lum as u32) < blackPoint {
|
||||||
|
col.set(x);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let mut left = localLuminances[0]; // & 0xff;
|
||||||
|
let mut center = localLuminances[1]; // & 0xff;
|
||||||
|
for x in 1..width - 1 {
|
||||||
|
// for (int x = 1; x < width - 1; x++) {
|
||||||
|
let right = localLuminances[x + 1];
|
||||||
|
// A simple -1 4 -1 box filter with a weight of 2.
|
||||||
|
if ((center as i64 * 4) - left as i64 - right as i64) / 2
|
||||||
|
< blackPoint as i64
|
||||||
|
{
|
||||||
|
col.set(x);
|
||||||
|
}
|
||||||
|
left = center;
|
||||||
|
center = right;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(col)
|
||||||
|
})?;
|
||||||
|
|
||||||
|
Ok(Cow::Borrowed(col))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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.
|
||||||
|
|||||||
216
src/filtered_image_reader.rs
Normal file
216
src/filtered_image_reader.rs
Normal file
@@ -0,0 +1,216 @@
|
|||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use crate::{Binarizer, BinaryBitmap, Exceptions, Luma8LuminanceSource, LuminanceSource, Reader};
|
||||||
|
|
||||||
|
use crate::common::{BitMatrix, Result};
|
||||||
|
|
||||||
|
pub const DEFAULT_DOWNSCALE_THRESHHOLD: usize = 500;
|
||||||
|
pub const DEFAULT_DOWNSCALE_FACTOR: usize = 3;
|
||||||
|
|
||||||
|
/// Passed image data is ignored, only the image data
|
||||||
|
pub struct FilteredImageReader<R: Reader, B: Binarizer<Source = Luma8LuminanceSource>> {
|
||||||
|
reader: R,
|
||||||
|
source: Luma8LuminanceSource,
|
||||||
|
binarizer: B,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<R: Reader, B: Binarizer<Source = Luma8LuminanceSource>> FilteredImageReader<R, B> {
|
||||||
|
pub fn new<I: LuminanceSource + Clone + Into<Luma8LuminanceSource>>(
|
||||||
|
reader: R,
|
||||||
|
source: I,
|
||||||
|
binarizer: B,
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
reader,
|
||||||
|
source: source.into(),
|
||||||
|
binarizer,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<R: Reader, B1: Binarizer<Source = Luma8LuminanceSource>> Reader
|
||||||
|
for FilteredImageReader<R, B1>
|
||||||
|
{
|
||||||
|
fn decode<B: crate::Binarizer>(
|
||||||
|
&mut self,
|
||||||
|
_image: &mut crate::BinaryBitmap<B>,
|
||||||
|
) -> crate::common::Result<crate::RXingResult> {
|
||||||
|
self.decode_with_hints(_image, &HashMap::default())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn decode_with_hints<B: crate::Binarizer>(
|
||||||
|
&mut self,
|
||||||
|
_image: &mut crate::BinaryBitmap<B>,
|
||||||
|
hints: &crate::DecodingHintDictionary,
|
||||||
|
) -> crate::common::Result<crate::RXingResult> {
|
||||||
|
let pyramids = LumImagePyramid::new(
|
||||||
|
self.source.clone(),
|
||||||
|
DEFAULT_DOWNSCALE_THRESHHOLD,
|
||||||
|
DEFAULT_DOWNSCALE_FACTOR,
|
||||||
|
)
|
||||||
|
.ok_or(Exceptions::ILLEGAL_ARGUMENT)?;
|
||||||
|
for layer in pyramids.layers {
|
||||||
|
let mut b = BinaryBitmap::new(self.binarizer.create_binarizer(layer));
|
||||||
|
for close in [false, true] {
|
||||||
|
if close {
|
||||||
|
let Ok(_) = b.close() else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if let Ok(res) = self.reader.decode_with_hints(&mut b, hints) {
|
||||||
|
return Ok(res);
|
||||||
|
} else {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(Exceptions::NOT_FOUND)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
struct LumImagePyramid {
|
||||||
|
buffers: Vec<Luma8LuminanceSource>,
|
||||||
|
pub layers: Vec<Luma8LuminanceSource>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for LumImagePyramid {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
buffers: Default::default(),
|
||||||
|
layers: Default::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LumImagePyramid {
|
||||||
|
pub fn new(image: Luma8LuminanceSource, threshold: usize, factor: usize) -> Option<Self> {
|
||||||
|
let mut new_self = Self::default();
|
||||||
|
|
||||||
|
new_self.layers.push(image);
|
||||||
|
// TODO: if only matrix codes were considered, then using std::min would be sufficient (see #425)
|
||||||
|
while threshold > 0
|
||||||
|
&& std::cmp::max(
|
||||||
|
new_self.layers.last()?.get_width(),
|
||||||
|
new_self.layers.last()?.get_height(),
|
||||||
|
) > threshold
|
||||||
|
&& std::cmp::min(
|
||||||
|
new_self.layers.last()?.get_width(),
|
||||||
|
new_self.layers.last()?.get_height(),
|
||||||
|
) >= factor
|
||||||
|
{
|
||||||
|
new_self.add_layer_with_factor(factor).ok()?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if false {
|
||||||
|
// Reversing the layers means we'd start with the smallest. that can make sense if we are only looking for a
|
||||||
|
// single symbol. If we start with the higher resolution, we get better (high res) position information.
|
||||||
|
// TODO: see if masking out higher res layers based on found symbols in lower res helps overall performance.
|
||||||
|
new_self.layers.reverse();
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(new_self)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_layer<const N: usize>(&mut self) -> Result<()> {
|
||||||
|
let siv = self.layers.last().ok_or(Exceptions::ILLEGAL_ARGUMENT)?;
|
||||||
|
|
||||||
|
self.buffers.push(Luma8LuminanceSource::with_empty_image(
|
||||||
|
siv.get_width() / N,
|
||||||
|
siv.get_height() / N,
|
||||||
|
));
|
||||||
|
|
||||||
|
let div = self
|
||||||
|
.buffers
|
||||||
|
.last_mut()
|
||||||
|
.ok_or(Exceptions::ILLEGAL_ARGUMENT)?;
|
||||||
|
|
||||||
|
let div_height = div.get_height();
|
||||||
|
let div_width = div.get_width();
|
||||||
|
|
||||||
|
let d_vec = div.get_matrix_mut();
|
||||||
|
|
||||||
|
for d in d_vec.iter_mut() {
|
||||||
|
for dy in 0..div_height {
|
||||||
|
// for (int dy = 0; dy < div.height(); ++dy){
|
||||||
|
for dx in 0..div_width {
|
||||||
|
// for (int dx = 0; dx < div.width(); ++dx) {
|
||||||
|
let mut sum = (N * N) as u8 / 2;
|
||||||
|
for ty in 0..N {
|
||||||
|
// for (int ty = 0; ty < N; ++ty){
|
||||||
|
for tx in 0..N {
|
||||||
|
// for (int tx = 0; tx < N; ++tx) {
|
||||||
|
sum += siv.get_luma8_point(dx * N + tx, dy * N + ty);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*d = sum / (N * N) as u8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.layers.push(
|
||||||
|
self.buffers
|
||||||
|
.last()
|
||||||
|
.ok_or(Exceptions::ILLEGAL_ARGUMENT)?
|
||||||
|
.clone(),
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_layer_with_factor(&mut self, factor: usize) -> Result<()> {
|
||||||
|
// help the compiler's auto-vectorizer by hard-coding the scale factor
|
||||||
|
match factor {
|
||||||
|
2 => self.add_layer::<2>(),
|
||||||
|
3 => self.add_layer::<3>(),
|
||||||
|
4 => self.add_layer::<4>(),
|
||||||
|
_ => Err(Exceptions::illegal_argument_with(
|
||||||
|
"Invalid ReaderOptions::downscaleFactor",
|
||||||
|
)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const SET_V: u32 = 0xff; // allows playing with SIMD binarization
|
||||||
|
|
||||||
|
impl<B: Binarizer> BinaryBitmap<B> {
|
||||||
|
pub fn close(&mut self) -> Result<()> {
|
||||||
|
if let Some(mut matrix) = self.matrix.as_mut() {
|
||||||
|
// if (_cache->matrix) {
|
||||||
|
// auto& matrix = *const_cast<BitMatrix*>(_cache->matrix.get());
|
||||||
|
let mut tmp = BitMatrix::new(matrix.width(), matrix.height())?;
|
||||||
|
|
||||||
|
// dilate
|
||||||
|
SumFilter(matrix, &mut tmp, |sum| {
|
||||||
|
return u32::from(sum > 0 * SET_V) * SET_V;
|
||||||
|
});
|
||||||
|
// erode
|
||||||
|
SumFilter(&tmp, &mut matrix, |sum| {
|
||||||
|
return u32::from(sum == 9 * SET_V) * SET_V;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
// _closed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn SumFilter<F>(input: &BitMatrix, output: &mut BitMatrix, func: F)
|
||||||
|
where
|
||||||
|
F: Fn(u32) -> u32,
|
||||||
|
{
|
||||||
|
for row in 1..output.height() {
|
||||||
|
for col in 0..output.width() - 1 {
|
||||||
|
let in0 = input.getRow(row); //.row(0).begin();
|
||||||
|
let in1 = input.getRow(row + 1); //.row(1).begin();
|
||||||
|
let in2 = input.getRow(row + 2); //.row(2).begin();
|
||||||
|
|
||||||
|
let mut sum = 0;
|
||||||
|
for j in 0..3 {
|
||||||
|
// for (int j = 0; j < 3; ++j){
|
||||||
|
sum += in0.get(j) as u32 + in1.get(j) as u32 + in2.get(j) as u32;
|
||||||
|
}
|
||||||
|
|
||||||
|
output.set_bool(row, col, func(sum) != 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -104,6 +104,9 @@ pub mod helpers;
|
|||||||
mod luma_luma_source;
|
mod luma_luma_source;
|
||||||
pub use luma_luma_source::*;
|
pub use luma_luma_source::*;
|
||||||
|
|
||||||
|
mod filtered_image_reader;
|
||||||
|
pub use filtered_image_reader::*;
|
||||||
|
|
||||||
#[cfg(feature = "svg_read")]
|
#[cfg(feature = "svg_read")]
|
||||||
mod svg_luminance_source;
|
mod svg_luminance_source;
|
||||||
#[cfg(feature = "svg_read")]
|
#[cfg(feature = "svg_read")]
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ use crate::common::Result;
|
|||||||
use crate::LuminanceSource;
|
use crate::LuminanceSource;
|
||||||
|
|
||||||
/// A simple luma8 source for bytes, supports cropping but not rotation
|
/// A simple luma8 source for bytes, supports cropping but not rotation
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
pub struct Luma8LuminanceSource {
|
pub struct Luma8LuminanceSource {
|
||||||
/// image dimension in form (x,y)
|
/// image dimension in form (x,y)
|
||||||
dimensions: (u32, u32),
|
dimensions: (u32, u32),
|
||||||
@@ -27,6 +28,19 @@ impl LuminanceSource for Luma8LuminanceSource {
|
|||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_column(&self, x: usize) -> Vec<u8> {
|
||||||
|
self.data
|
||||||
|
.chunks_exact(self.original_dimension.0 as usize)
|
||||||
|
.skip(self.origin.1 as usize)
|
||||||
|
.fold(Vec::default(), |mut acc, e| {
|
||||||
|
acc.push(e[self.origin.0 as usize + x as usize]);
|
||||||
|
acc
|
||||||
|
})
|
||||||
|
.iter()
|
||||||
|
.map(|byte| Self::invert_if_should(*byte, self.inverted))
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
fn get_matrix(&self) -> Vec<u8> {
|
fn get_matrix(&self) -> Vec<u8> {
|
||||||
self.data
|
self.data
|
||||||
.iter()
|
.iter()
|
||||||
@@ -93,6 +107,10 @@ impl LuminanceSource for Luma8LuminanceSource {
|
|||||||
"This luminance source does not support rotation by 45 degrees.",
|
"This luminance source does not support rotation by 45 degrees.",
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_luma8_point(&self, x: usize, y: usize) -> u8 {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Luma8LuminanceSource {
|
impl Luma8LuminanceSource {
|
||||||
@@ -159,6 +177,20 @@ impl Luma8LuminanceSource {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn with_empty_image(width: usize, height: usize) -> Self {
|
||||||
|
Self {
|
||||||
|
dimensions: (width as u32, height as u32),
|
||||||
|
origin: (0, 0),
|
||||||
|
data: vec![0u8; width * height],
|
||||||
|
inverted: false,
|
||||||
|
original_dimension: (width as u32, height as u32),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_matrix_mut(&mut self) -> &mut Vec<u8> {
|
||||||
|
&mut self.data
|
||||||
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn invert_if_should(byte: u8, invert: bool) -> u8 {
|
fn invert_if_should(byte: u8, invert: bool) -> u8 {
|
||||||
if invert {
|
if invert {
|
||||||
|
|||||||
@@ -48,6 +48,9 @@ pub trait LuminanceSource {
|
|||||||
*/
|
*/
|
||||||
fn get_row(&self, y: usize) -> Vec<u8>;
|
fn get_row(&self, y: usize) -> Vec<u8>;
|
||||||
|
|
||||||
|
/// Get a column of of the image
|
||||||
|
fn get_column(&self, x: 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:
|
||||||
* {@code int luminance = array[y * width + x] & 0xff}
|
* {@code int luminance = array[y * width + x] & 0xff}
|
||||||
@@ -149,6 +152,8 @@ pub trait LuminanceSource {
|
|||||||
iv
|
iv
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_luma8_point(&self, x: usize, y: usize) -> u8;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@Override
|
@Override
|
||||||
public final String toString() {
|
public final String toString() {
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
|
|
||||||
use crate::common::Result;
|
use crate::common::Result;
|
||||||
|
use crate::oned::cpp::ODReader;
|
||||||
use crate::qrcode::cpp_port::QrReader;
|
use crate::qrcode::cpp_port::QrReader;
|
||||||
use crate::{
|
use crate::{
|
||||||
aztec::AztecReader, datamatrix::DataMatrixReader, maxicode::MaxiCodeReader,
|
aztec::AztecReader, datamatrix::DataMatrixReader, maxicode::MaxiCodeReader,
|
||||||
@@ -194,6 +195,9 @@ impl MultiFormatReader {
|
|||||||
BarcodeFormat::MAXICODE => {
|
BarcodeFormat::MAXICODE => {
|
||||||
MaxiCodeReader::default().decode_with_hints(image, &self.hints)
|
MaxiCodeReader::default().decode_with_hints(image, &self.hints)
|
||||||
}
|
}
|
||||||
|
BarcodeFormat::DXFilmEdge => {
|
||||||
|
ODReader::new(&self.hints).decode_with_hints(image, &self.hints)
|
||||||
|
}
|
||||||
_ => Err(Exceptions::UNSUPPORTED_OPERATION),
|
_ => Err(Exceptions::UNSUPPORTED_OPERATION),
|
||||||
};
|
};
|
||||||
if res.is_ok() {
|
if res.is_ok() {
|
||||||
@@ -230,6 +234,9 @@ impl MultiFormatReader {
|
|||||||
if let Ok(res) = MaxiCodeReader::default().decode_with_hints(image, &self.hints) {
|
if let Ok(res) = MaxiCodeReader::default().decode_with_hints(image, &self.hints) {
|
||||||
return Ok(res);
|
return Ok(res);
|
||||||
}
|
}
|
||||||
|
if let Ok(res) = ODReader::new(&self.hints).decode_with_hints(image, &self.hints) {
|
||||||
|
return Ok(res);
|
||||||
|
}
|
||||||
|
|
||||||
if self.try_harder {
|
if self.try_harder {
|
||||||
if let Ok(res) = self.one_d_reader.decode_with_hints(image, &self.hints) {
|
if let Ok(res) = self.one_d_reader.decode_with_hints(image, &self.hints) {
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ fn DistIsBelowThreshold(a: PointI, b: PointI, threshold: PointI) -> bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// DX Film Edge clock track found on 35mm films.
|
// DX Film Edge clock track found on 35mm films.
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Clone)]
|
||||||
pub(super) struct Clock {
|
pub(super) struct Clock {
|
||||||
hasFrameNr: bool, // = false; // Clock track (thus data track) with frame number (longer version)
|
hasFrameNr: bool, // = false; // Clock track (thus data track) with frame number (longer version)
|
||||||
rowNumber: u32, // = 0,
|
rowNumber: u32, // = 0,
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ use crate::{Binarizer, DecodeHintType, DecodeHintValue};
|
|||||||
use crate::common::{LineOrientation, Quadrilateral, Result};
|
use crate::common::{LineOrientation, Quadrilateral, Result};
|
||||||
|
|
||||||
use super::dxfilm_edge_reader::DXFilmEdgeReader;
|
use super::dxfilm_edge_reader::DXFilmEdgeReader;
|
||||||
use super::row_reader::RowReader;
|
use super::row_reader::{DecodingState, RowReader};
|
||||||
|
|
||||||
pub struct ODReader<'a> {
|
pub struct ODReader<'a> {
|
||||||
reader: DXFilmEdgeReader<'a>, // THIS IS WRONG, SEE BELOW ONLY DOES ONE
|
reader: DXFilmEdgeReader<'a>, // THIS IS WRONG, SEE BELOW ONLY DOES ONE
|
||||||
@@ -47,11 +47,11 @@ impl<'a> ODReader<'_> {
|
|||||||
isPure: bool,
|
isPure: bool,
|
||||||
maxSymbols: u32,
|
maxSymbols: u32,
|
||||||
minLineCount: u32,
|
minLineCount: u32,
|
||||||
returnErrors: bool,
|
_returnErrors: bool,
|
||||||
) -> Vec<RXingResult> {
|
) -> Vec<RXingResult> {
|
||||||
let mut res: Vec<Option<RXingResult>> = Vec::new();
|
let mut res: Vec<Option<RXingResult>> = Vec::new();
|
||||||
|
|
||||||
let mut decodingState: Vec<&mut Option<super::row_reader::DecodingState>> = Vec::new();
|
let mut decodingState: Vec<Option<DecodingState>> = vec![Some(DecodingState::default()); 1];
|
||||||
// std::vector<std::unique_ptr<RowReader::DecodingState>> decodingState(readers.size());
|
// std::vector<std::unique_ptr<RowReader::DecodingState>> decodingState(readers.size());
|
||||||
|
|
||||||
let mut minLineCount = minLineCount;
|
let mut minLineCount = minLineCount;
|
||||||
@@ -120,6 +120,7 @@ impl<'a> ODReader<'_> {
|
|||||||
checkRows.pop();
|
checkRows.pop();
|
||||||
isCheckRow = true;
|
isCheckRow = true;
|
||||||
if (rowNumber < 0 || rowNumber >= height) {
|
if (rowNumber < 0 || rowNumber >= height) {
|
||||||
|
i += 1;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -134,6 +135,7 @@ impl<'a> ODReader<'_> {
|
|||||||
) {
|
) {
|
||||||
r.as_ref().into()
|
r.as_ref().into()
|
||||||
} else {
|
} else {
|
||||||
|
i += 1;
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
// let img = if rotate {let a = image.rotate_counter_clockwise(); &a} else {image};
|
// let img = if rotate {let a = image.rotate_counter_clockwise(); &a} else {image};
|
||||||
@@ -182,7 +184,7 @@ impl<'a> ODReader<'_> {
|
|||||||
let mut next = PatternView::new(&bars);
|
let mut next = PatternView::new(&bars);
|
||||||
loop {
|
loop {
|
||||||
let mut result_hld = readers[r]
|
let mut result_hld = readers[r]
|
||||||
.decodePattern(rowNumber as u32, &mut next, decodingState[r])
|
.decodePattern(rowNumber as u32, &mut next, &mut decodingState[r])
|
||||||
.ok();
|
.ok();
|
||||||
if result_hld.is_some()
|
if result_hld.is_some()
|
||||||
/*|| (returnErrors && result.is_none())*/
|
/*|| (returnErrors && result.is_none())*/
|
||||||
@@ -277,6 +279,7 @@ impl<'a> ODReader<'_> {
|
|||||||
// make sure we make progress and we start the next try on a bar
|
// make sure we make progress and we start the next try on a bar
|
||||||
next.shift(2 - (next.index() % 2));
|
next.shift(2 - (next.index() % 2));
|
||||||
next.extend();
|
next.extend();
|
||||||
|
|
||||||
if !(tryHarder && next.size() > 0) {
|
if !(tryHarder && next.size() > 0) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -371,29 +374,7 @@ impl<'a> ODReader<'_> {
|
|||||||
_hints: &DecodingHintDictionary,
|
_hints: &DecodingHintDictionary,
|
||||||
image: &BinaryBitmap<B>,
|
image: &BinaryBitmap<B>,
|
||||||
) -> Result<RXingResult> {
|
) -> Result<RXingResult> {
|
||||||
let mut result = Self::DoDecode(
|
let result = self.decode_with_max_symbols(_hints, image, u32::MAX)?;
|
||||||
&self.reader,
|
|
||||||
image,
|
|
||||||
self.try_harder,
|
|
||||||
false,
|
|
||||||
self.is_pure,
|
|
||||||
1,
|
|
||||||
self.min_line_count,
|
|
||||||
self.return_errors,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (result.is_empty() && self.try_rotate) {
|
|
||||||
result = Self::DoDecode(
|
|
||||||
&self.reader,
|
|
||||||
image,
|
|
||||||
self.try_harder,
|
|
||||||
true,
|
|
||||||
self.is_pure,
|
|
||||||
1,
|
|
||||||
self.min_line_count,
|
|
||||||
self.return_errors,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
result.first().cloned().ok_or(Exceptions::NOT_FOUND)
|
result.first().cloned().ok_or(Exceptions::NOT_FOUND)
|
||||||
// return FirstOrDefault(std::move(result));
|
// return FirstOrDefault(std::move(result));
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ type Alphabet = Vec<char>;
|
|||||||
// // virtual ~DecodingState() = default;
|
// // virtual ~DecodingState() = default;
|
||||||
// }
|
// }
|
||||||
|
|
||||||
#[derive(Default, Debug)]
|
#[derive(Default, Debug, Clone)]
|
||||||
pub struct DecodingState {
|
pub struct DecodingState {
|
||||||
// DXO
|
// DXO
|
||||||
pub centerRow: u32,
|
pub centerRow: u32,
|
||||||
|
|||||||
@@ -256,6 +256,10 @@ impl LuminanceSource for PlanarYUVLuminanceSource {
|
|||||||
row
|
row
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_column(&self, x: usize) -> Vec<u8> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
fn get_matrix(&self) -> Vec<u8> {
|
fn get_matrix(&self) -> Vec<u8> {
|
||||||
let width = self.get_width();
|
let width = self.get_width();
|
||||||
let height = self.get_height();
|
let height = self.get_height();
|
||||||
@@ -332,4 +336,8 @@ impl LuminanceSource for PlanarYUVLuminanceSource {
|
|||||||
fn invert(&mut self) {
|
fn invert(&mut self) {
|
||||||
self.invert = !self.invert;
|
self.invert = !self.invert;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_luma8_point(&self, x: usize, y: usize) -> u8 {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -58,6 +58,10 @@ impl LuminanceSource for RGBLuminanceSource {
|
|||||||
row
|
row
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_column(&self, x: usize) -> Vec<u8> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
fn get_matrix(&self) -> Vec<u8> {
|
fn get_matrix(&self) -> Vec<u8> {
|
||||||
let width = self.get_width();
|
let width = self.get_width();
|
||||||
let height = self.get_height();
|
let height = self.get_height();
|
||||||
@@ -127,6 +131,14 @@ impl LuminanceSource for RGBLuminanceSource {
|
|||||||
fn invert(&mut self) {
|
fn invert(&mut self) {
|
||||||
self.invert = !self.invert;
|
self.invert = !self.invert;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_luma8_point(&self, x: usize, y: usize) -> u8 {
|
||||||
|
let width = self.get_width();
|
||||||
|
let row_offset = (y + self.top) * self.dataWidth + self.left;
|
||||||
|
let col_offset = (x + self.left);
|
||||||
|
|
||||||
|
self.luminances[row_offset + col_offset]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RGBLuminanceSource {
|
impl RGBLuminanceSource {
|
||||||
|
|||||||
@@ -11,6 +11,10 @@ impl LuminanceSource for SVGLuminanceSource {
|
|||||||
self.0.get_row(y)
|
self.0.get_row(y)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_column(&self, x: usize) -> Vec<u8> {
|
||||||
|
self.0.get_column(x)
|
||||||
|
}
|
||||||
|
|
||||||
fn get_matrix(&self) -> Vec<u8> {
|
fn get_matrix(&self) -> Vec<u8> {
|
||||||
self.0.get_matrix()
|
self.0.get_matrix()
|
||||||
}
|
}
|
||||||
@@ -46,6 +50,10 @@ impl LuminanceSource for SVGLuminanceSource {
|
|||||||
fn rotate_counter_clockwise_45(&self) -> Result<Self> {
|
fn rotate_counter_clockwise_45(&self) -> Result<Self> {
|
||||||
self.0.rotate_counter_clockwise_45().map(Self)
|
self.0.rotate_counter_clockwise_45().map(Self)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_luma8_point(&self, x: usize, y: usize) -> u8 {
|
||||||
|
self.0.get_luma8_point(x, y)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SVGLuminanceSource {
|
impl SVGLuminanceSource {
|
||||||
|
|||||||
BIN
test_resources/blackbox/dxfilmedge-1/1.jpg
Normal file
BIN
test_resources/blackbox/dxfilmedge-1/1.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 25 KiB |
1
test_resources/blackbox/dxfilmedge-1/1.txt
Normal file
1
test_resources/blackbox/dxfilmedge-1/1.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
36-2/21
|
||||||
BIN
test_resources/blackbox/dxfilmedge-1/2.png
Normal file
BIN
test_resources/blackbox/dxfilmedge-1/2.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 16 KiB |
1
test_resources/blackbox/dxfilmedge-1/2.txt
Normal file
1
test_resources/blackbox/dxfilmedge-1/2.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
80-11/23
|
||||||
BIN
test_resources/blackbox/dxfilmedge-1/3.jpg
Normal file
BIN
test_resources/blackbox/dxfilmedge-1/3.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.6 KiB |
1
test_resources/blackbox/dxfilmedge-1/3.txt
Normal file
1
test_resources/blackbox/dxfilmedge-1/3.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
10-3
|
||||||
27
tests/dx_film_edge.rs
Normal file
27
tests/dx_film_edge.rs
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
// dxfilmedge-1
|
||||||
|
|
||||||
|
#![cfg(feature = "image")]
|
||||||
|
|
||||||
|
use rxing::{BarcodeFormat, MultiFormatReader};
|
||||||
|
|
||||||
|
mod common;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Sean Owen
|
||||||
|
*/
|
||||||
|
#[cfg(feature = "image-formats")]
|
||||||
|
#[test]
|
||||||
|
fn dx_film_edge() {
|
||||||
|
let mut tester = common::AbstractBlackBoxTestCase::new(
|
||||||
|
"test_resources/blackbox/dxfilmedge-1",
|
||||||
|
MultiFormatReader::default(),
|
||||||
|
BarcodeFormat::DXFilmEdge,
|
||||||
|
);
|
||||||
|
|
||||||
|
tester.add_test(1, 2, 0.0);
|
||||||
|
tester.add_test(1, 2, 90.0);
|
||||||
|
tester.add_test(1, 2, 180.0);
|
||||||
|
tester.add_test(1, 2, 320.0);
|
||||||
|
|
||||||
|
tester.test_black_box()
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user