mirror of
https://github.com/starovoid/rxing.git
synced 2026-07-26 04:12:34 +00:00
in_progress port from cpp
This commit is contained in:
@@ -499,6 +499,24 @@ impl std::ops::Sub for ConcentricPattern {
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::Add for ConcentricPattern {
|
||||
type Output = Self;
|
||||
|
||||
fn add(self, rhs: Self) -> Self::Output {
|
||||
let new_p = self.p - rhs.p;
|
||||
Self {
|
||||
p: new_p,
|
||||
size: self.size,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Point> for ConcentricPattern {
|
||||
fn from(value: Point) -> Self {
|
||||
Self { p: value, size: 0 }
|
||||
}
|
||||
}
|
||||
|
||||
impl ConcentricPattern {
|
||||
pub fn dot(self, other: ConcentricPattern) -> f32 {
|
||||
Point::dot(self.p, other.p)
|
||||
|
||||
@@ -223,6 +223,12 @@ impl RegressionLineTrait for DMRegressionLine {
|
||||
}
|
||||
|
||||
impl DMRegressionLine {
|
||||
pub fn new(point_1: Point, point_2: Point) -> Self {
|
||||
let mut new = Self::default();
|
||||
RegressionLineTrait::evaluate(&mut new, &[point_1, point_1]);
|
||||
new
|
||||
}
|
||||
|
||||
// template <typename Container, typename Filter>
|
||||
fn average<T>(c: &[f64], f: T) -> f64
|
||||
where
|
||||
|
||||
106
src/common/cpp_essentials/matrix.rs
Normal file
106
src/common/cpp_essentials/matrix.rs
Normal file
@@ -0,0 +1,106 @@
|
||||
use crate::common::Result;
|
||||
use crate::{Exceptions, Point};
|
||||
|
||||
#[derive(Default, Clone, PartialEq, Eq)]
|
||||
pub struct Matrix<T: Default + Clone + Copy> {
|
||||
width: usize,
|
||||
height: usize,
|
||||
data: Vec<T>,
|
||||
}
|
||||
|
||||
impl<T: Default + Clone + Copy> Matrix<T> {
|
||||
pub fn with_data(width: usize, height: usize, data: Vec<T>) -> Result<Matrix<T>> {
|
||||
if (width != 0 && data.len() / width as usize != height as usize) {
|
||||
return Err(Exceptions::illegal_argument_with(
|
||||
"invalid size: width * height is too big",
|
||||
));
|
||||
}
|
||||
Ok(Self {
|
||||
width,
|
||||
height,
|
||||
data,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn new(width: usize, height: usize) -> Result<Matrix<T>> {
|
||||
if (width != 0 && height != 0) {
|
||||
return Err(Exceptions::illegal_argument_with(
|
||||
"invalid size: width * height is too big",
|
||||
));
|
||||
}
|
||||
Ok(Self {
|
||||
width,
|
||||
height,
|
||||
data: vec![T::default(); width * height],
|
||||
})
|
||||
}
|
||||
|
||||
pub fn height(&self) -> usize {
|
||||
self.height
|
||||
}
|
||||
|
||||
pub fn width(&self) -> usize {
|
||||
self.width
|
||||
}
|
||||
|
||||
pub fn size(&self) -> usize {
|
||||
self.data.len()
|
||||
}
|
||||
|
||||
// value_t& operator()(int x, int y)
|
||||
// {
|
||||
// assert(x >= 0 && x < _width && y >= 0 && y < _height);
|
||||
// return _data[y * _width + x];
|
||||
// }
|
||||
|
||||
// const T& operator()(int x, int y) const
|
||||
// {
|
||||
// assert(x >= 0 && x < _width && y >= 0 && y < _height);
|
||||
// return _data[y * _width + x];
|
||||
// }
|
||||
|
||||
fn get_offset(x: usize, y: usize, width: usize) -> usize {
|
||||
(y * width + x) as usize
|
||||
}
|
||||
|
||||
pub fn get(&self, x: usize, y: usize) -> Option<T> {
|
||||
if x >= 0 && x < self.width && y >= 0 && y < self.height {
|
||||
None
|
||||
} else {
|
||||
Some(self.data[Self::get_offset(x, y, self.width)])
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set(&mut self, x: usize, y: usize, value: T) -> T {
|
||||
self.data[Self::get_offset(x, y, self.width)] = value;
|
||||
self.get(x, y).unwrap()
|
||||
}
|
||||
|
||||
pub fn get_point(&self, p: Point) -> Option<T> {
|
||||
self.get(p.x as usize, p.y as usize)
|
||||
}
|
||||
|
||||
pub fn set_point(&mut self, p: Point, value: T) -> T {
|
||||
self.set(p.x as usize, p.y as usize, value)
|
||||
}
|
||||
|
||||
pub fn data(&self) -> &[T] {
|
||||
&self.data
|
||||
}
|
||||
|
||||
// const value_t* begin() const {
|
||||
// return _data.data();
|
||||
// }
|
||||
|
||||
// const value_t* end() const {
|
||||
// return _data.data() + _width * _height;
|
||||
// }
|
||||
|
||||
pub fn clear_with(&mut self, value: T) {
|
||||
self.data.fill(value)
|
||||
}
|
||||
|
||||
pub fn clear(&mut self) {
|
||||
self.data.fill(T::default())
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@ pub mod direction;
|
||||
pub mod dm_regression_line;
|
||||
pub mod edge_tracer;
|
||||
pub mod fast_edge_to_edge_counter;
|
||||
pub mod matrix;
|
||||
pub mod pattern;
|
||||
pub mod regression_line;
|
||||
pub mod regression_line_trait;
|
||||
@@ -19,6 +20,7 @@ pub use direction::*;
|
||||
pub use dm_regression_line::*;
|
||||
pub use edge_tracer::*;
|
||||
pub use fast_edge_to_edge_counter::*;
|
||||
pub use matrix::*;
|
||||
pub use pattern::*;
|
||||
pub use regression_line::*;
|
||||
pub use regression_line_trait::*;
|
||||
|
||||
@@ -29,6 +29,7 @@ use super::Quadrilateral;
|
||||
*
|
||||
* @author Sean Owen
|
||||
*/
|
||||
#[derive(Debug, Copy, Clone, PartialEq)]
|
||||
pub struct PerspectiveTransform {
|
||||
a11: f32,
|
||||
a12: f32,
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
use crate::Point;
|
||||
use crate::{point, Point};
|
||||
|
||||
use super::PerspectiveTransform;
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct Quadrilateral(pub [Point; 4]);
|
||||
@@ -74,6 +76,16 @@ impl Quadrilateral {
|
||||
])
|
||||
}
|
||||
|
||||
pub fn rectangle_from_xy(x0: f32, x1: f32, y0: f32, y1: f32, o: Option<f32>) -> Self {
|
||||
let o = o.unwrap_or(0.5);
|
||||
Quadrilateral::from([
|
||||
point(x0 + o, y0 + o),
|
||||
point(x1 + o, y0 + o),
|
||||
point(x1 + o, y1 + o),
|
||||
point(x0 + o, y1 + o),
|
||||
])
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn centered_square(size: i32) -> Quadrilateral {
|
||||
Self::scale(
|
||||
@@ -256,3 +268,9 @@ impl std::ops::IndexMut<usize> for Quadrilateral {
|
||||
&mut self.0[index]
|
||||
}
|
||||
}
|
||||
|
||||
impl From<[Point; 4]> for Quadrilateral {
|
||||
fn from(value: [Point; 4]) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,15 @@
|
||||
use crate::common::{cpp_essentials::CenterOfRing, Result};
|
||||
use crate::{
|
||||
common::{
|
||||
cpp_essentials::{CenterOfRing, DMRegressionLine, FindConcentricPatternCorners, Matrix},
|
||||
DefaultGridSampler, GridSampler, Result, SamplerControl,
|
||||
},
|
||||
dimension, point_g, point_i,
|
||||
qrcode::{
|
||||
decoder::{Version, VersionRef},
|
||||
detector::QRCodeDetectorResult,
|
||||
},
|
||||
Exceptions,
|
||||
};
|
||||
use multimap::MultiMap;
|
||||
|
||||
use crate::{
|
||||
@@ -406,3 +417,329 @@ pub fn LocateAlignmentPattern(
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
pub fn ReadVersion(
|
||||
image: &BitMatrix,
|
||||
dimension: u32,
|
||||
mod2Pix: PerspectiveTransform,
|
||||
) -> Result<VersionRef> {
|
||||
let mut bits = [0; 2]; //
|
||||
|
||||
for mirror in [false, true] {
|
||||
// Read top-right/bottom-left version info: 3 wide by 6 tall (depending on mirrored)
|
||||
let mut versionBits = 0;
|
||||
for y in (0..5).rev() {
|
||||
// for (int y = 5; y >= 0; --y)
|
||||
for x in ((dimension - 11)..(dimension - 9)).rev() {
|
||||
// for (int x = dimension - 9; x >= dimension - 11; --x) {
|
||||
let mod_ = if mirror { point_i(y, x) } else { point_i(x, y) };
|
||||
let pix = mod2Pix.transform_point((mod_).centered());
|
||||
if (!image.is_in(pix)) {
|
||||
versionBits = -1;
|
||||
} else {
|
||||
AppendBit(&mut versionBits, image.get_point(pix));
|
||||
}
|
||||
// log(pix, 3);
|
||||
}
|
||||
bits[usize::from(mirror)] = versionBits;
|
||||
}
|
||||
}
|
||||
|
||||
Version::DecodeVersionInformation(bits[0], bits[1])
|
||||
}
|
||||
|
||||
fn AppendBit(val: &mut i32, bit: bool) {
|
||||
*val <<= 1;
|
||||
|
||||
*val |= i32::from(bit)
|
||||
}
|
||||
|
||||
pub fn SampleQR(image: &BitMatrix, fp: &FinderPatternSet) -> Result<QRCodeDetectorResult> {
|
||||
let top = EstimateDimension(image, fp.tl, fp.tr);
|
||||
let left = EstimateDimension(image, fp.tl, fp.bl);
|
||||
|
||||
if (!(top.dim != 0) && !(left.dim != 0)) {
|
||||
return Err(Exceptions::NOT_FOUND);
|
||||
}
|
||||
|
||||
let best = if top.err == left.err {
|
||||
(if top.dim > left.dim { top } else { left })
|
||||
} else {
|
||||
(if top.err < left.err { top } else { left })
|
||||
};
|
||||
let mut dimension = best.dim;
|
||||
let moduleSize = (best.ms + 1.0) as i32;
|
||||
|
||||
let mut br = ConcentricPattern {
|
||||
p: point(-1.0, -1.0),
|
||||
size: 0,
|
||||
};
|
||||
let mut brOffset = point_i(3, 3);
|
||||
|
||||
// Everything except version 1 (21 modules) has an alignment pattern. Estimate the center of that by intersecting
|
||||
// line extensions of the 1 module wide square around the finder patterns. This could also help with detecting
|
||||
// slanted symbols of version 1.
|
||||
|
||||
// generate 4 lines: outer and inner edge of the 1 module wide black line between the two outer and the inner
|
||||
// (tl) finder pattern
|
||||
let bl2 = TraceLine(image, fp.bl.p, fp.tl.p, 2);
|
||||
let bl3 = TraceLine(image, fp.bl.p, fp.tl.p, 3);
|
||||
let tr2 = TraceLine(image, fp.tr.p, fp.tl.p, 2);
|
||||
let tr3 = TraceLine(image, fp.tr.p, fp.tl.p, 3);
|
||||
|
||||
if (bl2.isValid() && tr2.isValid() && bl3.isValid() && tr3.isValid()) {
|
||||
// intersect both outer and inner line pairs and take the center point between the two intersection points
|
||||
let brInter = (DMRegressionLine::intersect(&bl2, &tr2).ok_or(Exceptions::NOT_FOUND)?
|
||||
+ DMRegressionLine::intersect(&bl3, &tr3).ok_or(Exceptions::NOT_FOUND)?)
|
||||
/ 2.0;
|
||||
// log(brInter, 3);
|
||||
|
||||
if (dimension > 21) {
|
||||
if let Some(brCP) = LocateAlignmentPattern(image, moduleSize, brInter) {
|
||||
br = brCP.into();
|
||||
}
|
||||
}
|
||||
|
||||
// if the symbol is tilted or the resolution of the RegressionLines is sufficient, use their intersection
|
||||
// as the best estimate (see discussion in #199 and test image estimate-tilt.jpg )
|
||||
if (!image.is_in(br.p)
|
||||
&& (EstimateTilt(fp) > 1.1
|
||||
|| (bl2.isHighRes() && bl3.isHighRes() && tr2.isHighRes() && tr3.isHighRes())))
|
||||
{
|
||||
br = brInter.into();
|
||||
}
|
||||
}
|
||||
|
||||
// otherwise the simple estimation used by upstream is used as a best guess fallback
|
||||
if (!image.is_in(br.p)) {
|
||||
br = fp.tr - fp.tl + fp.bl;
|
||||
brOffset = point_i(0, 0);
|
||||
}
|
||||
|
||||
// log(br, 3);
|
||||
let mut mod2Pix = Mod2Pix(
|
||||
dimension,
|
||||
brOffset,
|
||||
Quadrilateral::from([fp.tl.p, fp.tr.p, br.p, fp.bl.p]),
|
||||
)?;
|
||||
|
||||
if (dimension >= Version::DimensionOfVersion(7, false) as i32) {
|
||||
let version = ReadVersion(image, dimension as u32, mod2Pix.clone());
|
||||
|
||||
// if the version bits are garbage -> discard the detection
|
||||
if (!version.is_ok()
|
||||
|| (version.as_ref().unwrap().getDimensionForVersion() as i32 - dimension).abs() > 8)
|
||||
{
|
||||
/*return DetectorResult();*/
|
||||
return Err(Exceptions::NOT_FOUND);
|
||||
}
|
||||
if (version.as_ref().unwrap().getDimensionForVersion() as i32 != dimension) {
|
||||
// printf("update dimension: %d -> %d\n", dimension, version.dimension());
|
||||
dimension = version.as_ref().unwrap().getDimensionForVersion() as i32;
|
||||
mod2Pix = Mod2Pix(
|
||||
dimension,
|
||||
brOffset,
|
||||
Quadrilateral::from([fp.tl.p, fp.tr.p, br.p, fp.bl.p]),
|
||||
)?;
|
||||
}
|
||||
// #if 1
|
||||
let apM = version.as_ref().unwrap().getAlignmentPatternCenters(); // alignment pattern positions in modules
|
||||
let mut apP = Matrix::new(apM.len(), apM.len())?; // found/guessed alignment pattern positions in pixels
|
||||
// let apP = Matrix<std::optional<PointF>>(Size(apM), Size(apM)); // found/guessed alignment pattern positions in pixels
|
||||
let N = (apM.len()) - 1;
|
||||
|
||||
// project the alignment pattern at module coordinates x/y to pixel coordinate based on current mod2Pix
|
||||
let projectM2P = /*[&mod2Pix, &apM]*/| x, y, mod2Pix: &PerspectiveTransform| { return mod2Pix.transform_point(Point::centered(point_i(apM[x], apM[y]))); };
|
||||
|
||||
let mut findInnerCornerOfConcentricPattern = /*[&image, &apP, &projectM2P]*/| x, y, fp:ConcentricPattern| {
|
||||
let pc = apP.set(x, y, projectM2P(x, y, &mod2Pix));
|
||||
if let Some(fpQuad) = FindConcentricPatternCorners(image, fp.p, fp.size, 2)
|
||||
// if (auto fpQuad = FindConcentricPatternCorners(image, fp, fp.size, 2))
|
||||
{for c in fpQuad .0
|
||||
{if (Point::distance(c, pc) < (fp.size as f32) / 2.0)
|
||||
{apP.set(x, y, c);}}}
|
||||
};
|
||||
|
||||
findInnerCornerOfConcentricPattern(0, 0, fp.tl);
|
||||
findInnerCornerOfConcentricPattern(0, N, fp.bl);
|
||||
findInnerCornerOfConcentricPattern(N, 0, fp.tr);
|
||||
|
||||
let bestGuessAPP = |x, y, apP: &Matrix<Point>| {
|
||||
if let Some(p) = apP.get(x, y)
|
||||
// if (auto p = apP(x, y))
|
||||
{
|
||||
return p;
|
||||
}
|
||||
return projectM2P(x, y, &mod2Pix);
|
||||
};
|
||||
|
||||
for y in 0..=N {
|
||||
// for (int y = 0; y <= N; ++y)
|
||||
for x in 0..=N {
|
||||
// for (int x = 0; x <= N; ++x) {
|
||||
if (apP.get(x, y).is_some()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let guessed = if x * y == 0 {
|
||||
bestGuessAPP(x, y, &apP)
|
||||
} else {
|
||||
bestGuessAPP(x - 1, y, &apP) + bestGuessAPP(x, y - 1, &apP)
|
||||
- bestGuessAPP(x - 1, y - 1, &apP)
|
||||
};
|
||||
if let Some(found) = LocateAlignmentPattern(image, moduleSize, guessed)
|
||||
// if (auto found = LocateAlignmentPattern(image, moduleSize, guessed))
|
||||
{
|
||||
apP.set(x, y, found);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// go over the whole set of alignment patters again and try to fill any remaining gap by using available neighbors as guides
|
||||
for y in 0..=N {
|
||||
// for (int y = 0; y <= N; ++y) {
|
||||
for x in 0..=N {
|
||||
// for (int x = 0; x <= N; ++x) {
|
||||
if (apP.get(x, y).is_some()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// find the two closest valid alignment pattern pixel positions both horizontally and vertically
|
||||
let mut hori = Vec::new();
|
||||
let mut verti = Vec::new();
|
||||
let mut i = 2;
|
||||
while i < 2 * N + 2 && hori.len() < 2 {
|
||||
let xi = x as isize + i as isize / 2 * (if i % 2 != 0 { 1 } else { -1 });
|
||||
if (0 <= xi && xi <= N as isize && apP.get(xi as usize, y).is_some()) {
|
||||
hori.push(
|
||||
apP.get(xi as usize, y)
|
||||
.ok_or(Exceptions::INDEX_OUT_OF_BOUNDS)?,
|
||||
);
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
// for (int i = 2; i < 2 * N + 2 && Size(hori) < 2; ++i) {
|
||||
// let xi = x + i / 2 * (i%2 ? 1 : -1);
|
||||
// if (0 <= xi && xi <= N && apP(xi, y))
|
||||
// {hori.push_back(*apP(xi, y));}
|
||||
// }
|
||||
let mut i = 2;
|
||||
while i < 2 * N + 2 && verti.len() < 2 {
|
||||
let yi = y as isize + i as isize / 2 * (if i % 2 != 0 { 1 } else { -1 });
|
||||
if (0 <= yi && yi <= N as isize && apP.get(x, yi as usize).is_some()) {
|
||||
verti.push(
|
||||
apP.get(x, yi as usize)
|
||||
.ok_or(Exceptions::INDEX_OUT_OF_BOUNDS)?,
|
||||
);
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
// for (int i = 2; i < 2 * N + 2 && Size(verti) < 2; ++i) {
|
||||
// let yi = y + i / 2 * (i%2 ? 1 : -1);
|
||||
// if (0 <= yi && yi <= N && apP(x, yi))
|
||||
// {verti.push_back(*apP(x, yi));}
|
||||
// }
|
||||
|
||||
// if we found 2 each, intersect the two lines that are formed by connecting the point pairs
|
||||
if ((hori.len()) == 2 && (verti.len()) == 2) {
|
||||
let guessed = RegressionLine::intersect(
|
||||
&DMRegressionLine::new(hori[0], hori[1]),
|
||||
&DMRegressionLine::new(verti[0], verti[1]),
|
||||
)
|
||||
.ok_or(Exceptions::ILLEGAL_STATE)?;
|
||||
let found = LocateAlignmentPattern(image, moduleSize, guessed);
|
||||
// search again near that intersection and if the search fails, use the intersection
|
||||
// if (!found.is_some()) {printf("location guessed at %dx%d\n", x, y)};
|
||||
apP.set(
|
||||
x,
|
||||
y,
|
||||
if found.is_some() {
|
||||
found.unwrap()
|
||||
} else {
|
||||
guessed
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(c) = apP.get(N, N)
|
||||
// if (auto c = apP.get(N, N))
|
||||
{
|
||||
mod2Pix = Mod2Pix(
|
||||
dimension,
|
||||
point_i(3, 3),
|
||||
Quadrilateral::from([fp.tl.p, fp.tr.p, c, fp.bl.p]),
|
||||
)?;
|
||||
}
|
||||
|
||||
// go over the whole set of alignment patters again and fill any remaining gaps by a projection based on an updated mod2Pix
|
||||
// projection. This works if the symbol is flat, wich is a reasonable fall-back assumption.
|
||||
for y in 0..=N {
|
||||
// for (int y = 0; y <= N; ++y) {
|
||||
for x in 0..=N {
|
||||
// for (int x = 0; x <= N; ++x) {
|
||||
if (apP.get(x, y).is_some()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// printf("locate failed at %dx%d\n", x, y);
|
||||
apP.set(x, y, projectM2P(x, y, &mod2Pix));
|
||||
}
|
||||
}
|
||||
|
||||
// assemble a list of region-of-interests based on the found alignment pattern pixel positions
|
||||
|
||||
let mut rois = Vec::new();
|
||||
for y in 0..N {
|
||||
// for (int y = 0; y < N; ++y){
|
||||
for x in 0..N {
|
||||
// for (int x = 0; x < N; ++x) {
|
||||
let x0 = apM[x];
|
||||
let x1 = apM[x + 1];
|
||||
let y0 = apM[y];
|
||||
let y1 = apM[y + 1];
|
||||
rois.push(SamplerControl {
|
||||
p0: point_i(x0 - u32::from(x == 0) * 6, x1 + u32::from(x == N - 1) * 7),
|
||||
p1: point_i(y0 - u32::from(y == 0) * 6, y1 + u32::from(y == N - 1) * 7),
|
||||
transform: PerspectiveTransform::quadrilateralToQuadrilateral(
|
||||
Quadrilateral::rectangle_from_xy(
|
||||
x0 as f32, x1 as f32, y0 as f32, y1 as f32, None,
|
||||
),
|
||||
Quadrilateral::from([
|
||||
apP.get(x, y).unwrap(),
|
||||
apP.get(x + 1, y).unwrap(),
|
||||
apP.get(x + 1, y + 1).unwrap(),
|
||||
apP.get(x, y + 1).unwrap(),
|
||||
]),
|
||||
)?,
|
||||
});
|
||||
}
|
||||
}
|
||||
let grid_sampler = DefaultGridSampler::default();
|
||||
let result = QRCodeDetectorResult::new(
|
||||
grid_sampler.sample_grid(image, dimension as u32, dimension as u32, &rois)?,
|
||||
Vec::default(),
|
||||
);
|
||||
return Ok(result);
|
||||
// grid_sampler.sample_grid(image, dimension, dimension, &rois);
|
||||
// #endif
|
||||
}
|
||||
|
||||
let grid_sampler = DefaultGridSampler::default();
|
||||
let result = QRCodeDetectorResult::new(
|
||||
grid_sampler.sample_grid(
|
||||
image,
|
||||
dimension as u32,
|
||||
dimension as u32,
|
||||
&[SamplerControl {
|
||||
p0: point_i(0, dimension as u32),
|
||||
p1: point_i(0, dimension as u32),
|
||||
transform: mod2Pix,
|
||||
}],
|
||||
)?,
|
||||
Vec::default(),
|
||||
);
|
||||
Ok(result)
|
||||
// return SampleGrid(image, dimension, dimension, mod2Pix);
|
||||
}
|
||||
|
||||
@@ -89,6 +89,18 @@ impl Version {
|
||||
17 + 4 * self.versionNumber
|
||||
}
|
||||
|
||||
pub fn DimensionOfVersion(version: u32, is_micro: bool) -> u32 {
|
||||
Self::DimensionOffset(is_micro) + Self::DimensionStep(is_micro) * version
|
||||
}
|
||||
|
||||
pub fn DimensionOffset(is_micro: bool) -> u32 {
|
||||
todo!()
|
||||
}
|
||||
|
||||
pub fn DimensionStep(is_micro: bool) -> u32 {
|
||||
todo!()
|
||||
}
|
||||
|
||||
pub fn getECBlocksForLevel(&self, ecLevel: ErrorCorrectionLevel) -> &ECBlocks {
|
||||
&self.ecBlocks[ecLevel.get_ordinal() as usize]
|
||||
}
|
||||
@@ -100,21 +112,21 @@ impl Version {
|
||||
* @return Version for a QR Code of that dimension
|
||||
* @throws FormatException if dimension is not 1 mod 4
|
||||
*/
|
||||
pub fn getProvisionalVersionForDimension(dimension: u32) -> Result<&'static Version> {
|
||||
pub fn getProvisionalVersionForDimension(dimension: u32) -> Result<VersionRef> {
|
||||
if dimension % 4 != 1 {
|
||||
return Err(Exceptions::format_with("dimension incorrect"));
|
||||
}
|
||||
Self::getVersionForNumber((dimension - 17) / 4)
|
||||
}
|
||||
|
||||
pub fn getVersionForNumber(versionNumber: u32) -> Result<&'static Version> {
|
||||
pub fn getVersionForNumber(versionNumber: u32) -> Result<VersionRef> {
|
||||
if !(1..=40).contains(&versionNumber) {
|
||||
return Err(Exceptions::illegal_argument_with("version out of spec"));
|
||||
}
|
||||
Ok(&VERSIONS[versionNumber as usize - 1])
|
||||
}
|
||||
|
||||
pub fn decodeVersionInformation(versionBits: u32) -> Result<&'static Version> {
|
||||
pub fn decodeVersionInformation(versionBits: u32) -> Result<VersionRef> {
|
||||
let mut bestDifference = u32::MAX;
|
||||
let mut bestVersion = 0;
|
||||
for i in 0..VERSION_DECODE_INFO.len() as u32 {
|
||||
@@ -140,6 +152,37 @@ impl Version {
|
||||
Err(Exceptions::NOT_FOUND)
|
||||
}
|
||||
|
||||
pub fn DecodeVersionInformation(versionBitsA: i32, versionBitsB: i32) -> Result<VersionRef> {
|
||||
let mut bestDifference = u32::MAX;
|
||||
let mut bestVersion = 0;
|
||||
let mut i = 0;
|
||||
for targetVersion in VERSION_DECODE_INFO {
|
||||
// for (int targetVersion : VERSION_DECODE_INFO) {
|
||||
// Do the version info bits match exactly? done.
|
||||
if targetVersion == versionBitsA as u32 || targetVersion == versionBitsB as u32 {
|
||||
return Self::getVersionForNumber(i + 7);
|
||||
}
|
||||
// Otherwise see if this is the closest to a real version info bit string
|
||||
// we have seen so far
|
||||
for bits in [versionBitsA, versionBitsB] {
|
||||
// for (int bits : {versionBitsA, versionBitsB}) {
|
||||
let bitsDifference = ((bits as u32) ^ targetVersion).count_ones(); //BitHacks::CountBitsSet(bits ^ targetVersion);
|
||||
if bitsDifference < bestDifference {
|
||||
bestVersion = i + 7;
|
||||
bestDifference = bitsDifference;
|
||||
}
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
// We can tolerate up to 3 bits of error since no two version info codewords will
|
||||
// differ in less than 8 bits.
|
||||
if bestDifference <= 3 {
|
||||
return Self::getVersionForNumber(bestVersion);
|
||||
}
|
||||
// If we didn't find a close enough match, fail
|
||||
return Err(Exceptions::ILLEGAL_STATE);
|
||||
}
|
||||
|
||||
/**
|
||||
* See ISO 18004:2006 Annex E
|
||||
*/
|
||||
|
||||
@@ -25,6 +25,14 @@ pub fn point(x: f32, y: f32) -> Point {
|
||||
Point::new(x, y)
|
||||
}
|
||||
|
||||
pub fn point_g<T: TryInto<f32>>(x: T, y: T) -> Option<Point> {
|
||||
Some(Point::new(x.try_into().ok()?, y.try_into().ok()?))
|
||||
}
|
||||
|
||||
pub fn point_i(x: u32, y: u32) -> Point {
|
||||
Point::new(x as f32, y as f32)
|
||||
}
|
||||
|
||||
/** Currently necessary because the external OneDReader proc macro uses it. */
|
||||
pub type RXingResultPoint = Point;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user