diff --git a/src/datamatrix/detector/Detector.java b/src/datamatrix/detector/Detector.java deleted file mode 100644 index a10ce46..0000000 --- a/src/datamatrix/detector/Detector.java +++ /dev/null @@ -1,383 +0,0 @@ -/* - * Copyright 2008 ZXing authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.zxing.datamatrix.detector; - -import com.google.zxing.NotFoundException; -import com.google.zxing.RXingResultPoint; -import com.google.zxing.common.BitMatrix; -import com.google.zxing.common.DetectorRXingResult; -import com.google.zxing.common.GridSampler; -import com.google.zxing.common.detector.WhiteRectangleDetector; - -/** - *

Encapsulates logic that can detect a Data Matrix Code in an image, even if the Data Matrix Code - * is rotated or skewed, or partially obscured.

- * - * @author Sean Owen - */ -public final class Detector { - - private final BitMatrix image; - private final WhiteRectangleDetector rectangleDetector; - - public Detector(BitMatrix image) throws NotFoundException { - this.image = image; - rectangleDetector = new WhiteRectangleDetector(image); - } - - /** - *

Detects a Data Matrix Code in an image.

- * - * @return {@link DetectorRXingResult} encapsulating results of detecting a Data Matrix Code - * @throws NotFoundException if no Data Matrix Code can be found - */ - public DetectorRXingResult detect() throws NotFoundException { - - RXingResultPoint[] cornerPoints = rectangleDetector.detect(); - - RXingResultPoint[] points = detectSolid1(cornerPoints); - points = detectSolid2(points); - points[3] = correctTopRight(points); - if (points[3] == null) { - throw NotFoundException.getNotFoundInstance(); - } - points = shiftToModuleCenter(points); - - RXingResultPoint topLeft = points[0]; - RXingResultPoint bottomLeft = points[1]; - RXingResultPoint bottomRight = points[2]; - RXingResultPoint topRight = points[3]; - - int dimensionTop = transitionsBetween(topLeft, topRight) + 1; - int dimensionRight = transitionsBetween(bottomRight, topRight) + 1; - if ((dimensionTop & 0x01) == 1) { - dimensionTop += 1; - } - if ((dimensionRight & 0x01) == 1) { - dimensionRight += 1; - } - - if (4 * dimensionTop < 6 * dimensionRight && 4 * dimensionRight < 6 * dimensionTop) { - // The matrix is square - dimensionTop = dimensionRight = Math.max(dimensionTop, dimensionRight); - } - - BitMatrix bits = sampleGrid(image, - topLeft, - bottomLeft, - bottomRight, - topRight, - dimensionTop, - dimensionRight); - - return new DetectorRXingResult(bits, new RXingResultPoint[]{topLeft, bottomLeft, bottomRight, topRight}); - } - - private static RXingResultPoint shiftPoint(RXingResultPoint point, RXingResultPoint to, int div) { - float x = (to.getX() - point.getX()) / (div + 1); - float y = (to.getY() - point.getY()) / (div + 1); - return new RXingResultPoint(point.getX() + x, point.getY() + y); - } - - private static RXingResultPoint moveAway(RXingResultPoint point, float fromX, float fromY) { - float x = point.getX(); - float y = point.getY(); - - if (x < fromX) { - x -= 1; - } else { - x += 1; - } - - if (y < fromY) { - y -= 1; - } else { - y += 1; - } - - return new RXingResultPoint(x, y); - } - - /** - * Detect a solid side which has minimum transition. - */ - private RXingResultPoint[] detectSolid1(RXingResultPoint[] cornerPoints) { - // 0 2 - // 1 3 - RXingResultPoint pointA = cornerPoints[0]; - RXingResultPoint pointB = cornerPoints[1]; - RXingResultPoint pointC = cornerPoints[3]; - RXingResultPoint pointD = cornerPoints[2]; - - int trAB = transitionsBetween(pointA, pointB); - int trBC = transitionsBetween(pointB, pointC); - int trCD = transitionsBetween(pointC, pointD); - int trDA = transitionsBetween(pointD, pointA); - - // 0..3 - // : : - // 1--2 - int min = trAB; - RXingResultPoint[] points = {pointD, pointA, pointB, pointC}; - if (min > trBC) { - min = trBC; - points[0] = pointA; - points[1] = pointB; - points[2] = pointC; - points[3] = pointD; - } - if (min > trCD) { - min = trCD; - points[0] = pointB; - points[1] = pointC; - points[2] = pointD; - points[3] = pointA; - } - if (min > trDA) { - points[0] = pointC; - points[1] = pointD; - points[2] = pointA; - points[3] = pointB; - } - - return points; - } - - /** - * Detect a second solid side next to first solid side. - */ - private RXingResultPoint[] detectSolid2(RXingResultPoint[] points) { - // A..D - // : : - // B--C - RXingResultPoint pointA = points[0]; - RXingResultPoint pointB = points[1]; - RXingResultPoint pointC = points[2]; - RXingResultPoint pointD = points[3]; - - // Transition detection on the edge is not stable. - // To safely detect, shift the points to the module center. - int tr = transitionsBetween(pointA, pointD); - RXingResultPoint pointBs = shiftPoint(pointB, pointC, (tr + 1) * 4); - RXingResultPoint pointCs = shiftPoint(pointC, pointB, (tr + 1) * 4); - int trBA = transitionsBetween(pointBs, pointA); - int trCD = transitionsBetween(pointCs, pointD); - - // 0..3 - // | : - // 1--2 - if (trBA < trCD) { - // solid sides: A-B-C - points[0] = pointA; - points[1] = pointB; - points[2] = pointC; - points[3] = pointD; - } else { - // solid sides: B-C-D - points[0] = pointB; - points[1] = pointC; - points[2] = pointD; - points[3] = pointA; - } - - return points; - } - - /** - * Calculates the corner position of the white top right module. - */ - private RXingResultPoint correctTopRight(RXingResultPoint[] points) { - // A..D - // | : - // B--C - RXingResultPoint pointA = points[0]; - RXingResultPoint pointB = points[1]; - RXingResultPoint pointC = points[2]; - RXingResultPoint pointD = points[3]; - - // shift points for safe transition detection. - int trTop = transitionsBetween(pointA, pointD); - int trRight = transitionsBetween(pointB, pointD); - RXingResultPoint pointAs = shiftPoint(pointA, pointB, (trRight + 1) * 4); - RXingResultPoint pointCs = shiftPoint(pointC, pointB, (trTop + 1) * 4); - - trTop = transitionsBetween(pointAs, pointD); - trRight = transitionsBetween(pointCs, pointD); - - RXingResultPoint candidate1 = new RXingResultPoint( - pointD.getX() + (pointC.getX() - pointB.getX()) / (trTop + 1), - pointD.getY() + (pointC.getY() - pointB.getY()) / (trTop + 1)); - RXingResultPoint candidate2 = new RXingResultPoint( - pointD.getX() + (pointA.getX() - pointB.getX()) / (trRight + 1), - pointD.getY() + (pointA.getY() - pointB.getY()) / (trRight + 1)); - - if (!isValid(candidate1)) { - if (isValid(candidate2)) { - return candidate2; - } - return null; - } - if (!isValid(candidate2)) { - return candidate1; - } - - int sumc1 = transitionsBetween(pointAs, candidate1) + transitionsBetween(pointCs, candidate1); - int sumc2 = transitionsBetween(pointAs, candidate2) + transitionsBetween(pointCs, candidate2); - - if (sumc1 > sumc2) { - return candidate1; - } else { - return candidate2; - } - } - - /** - * Shift the edge points to the module center. - */ - private RXingResultPoint[] shiftToModuleCenter(RXingResultPoint[] points) { - // A..D - // | : - // B--C - RXingResultPoint pointA = points[0]; - RXingResultPoint pointB = points[1]; - RXingResultPoint pointC = points[2]; - RXingResultPoint pointD = points[3]; - - // calculate pseudo dimensions - int dimH = transitionsBetween(pointA, pointD) + 1; - int dimV = transitionsBetween(pointC, pointD) + 1; - - // shift points for safe dimension detection - RXingResultPoint pointAs = shiftPoint(pointA, pointB, dimV * 4); - RXingResultPoint pointCs = shiftPoint(pointC, pointB, dimH * 4); - - // calculate more precise dimensions - dimH = transitionsBetween(pointAs, pointD) + 1; - dimV = transitionsBetween(pointCs, pointD) + 1; - if ((dimH & 0x01) == 1) { - dimH += 1; - } - if ((dimV & 0x01) == 1) { - dimV += 1; - } - - // WhiteRectangleDetector returns points inside of the rectangle. - // I want points on the edges. - float centerX = (pointA.getX() + pointB.getX() + pointC.getX() + pointD.getX()) / 4; - float centerY = (pointA.getY() + pointB.getY() + pointC.getY() + pointD.getY()) / 4; - pointA = moveAway(pointA, centerX, centerY); - pointB = moveAway(pointB, centerX, centerY); - pointC = moveAway(pointC, centerX, centerY); - pointD = moveAway(pointD, centerX, centerY); - - RXingResultPoint pointBs; - RXingResultPoint pointDs; - - // shift points to the center of each modules - pointAs = shiftPoint(pointA, pointB, dimV * 4); - pointAs = shiftPoint(pointAs, pointD, dimH * 4); - pointBs = shiftPoint(pointB, pointA, dimV * 4); - pointBs = shiftPoint(pointBs, pointC, dimH * 4); - pointCs = shiftPoint(pointC, pointD, dimV * 4); - pointCs = shiftPoint(pointCs, pointB, dimH * 4); - pointDs = shiftPoint(pointD, pointC, dimV * 4); - pointDs = shiftPoint(pointDs, pointA, dimH * 4); - - return new RXingResultPoint[]{pointAs, pointBs, pointCs, pointDs}; - } - - private boolean isValid(RXingResultPoint p) { - return p.getX() >= 0 && p.getX() <= image.getWidth() - 1 && p.getY() > 0 && p.getY() <= image.getHeight() - 1; - } - - private static BitMatrix sampleGrid(BitMatrix image, - RXingResultPoint topLeft, - RXingResultPoint bottomLeft, - RXingResultPoint bottomRight, - RXingResultPoint topRight, - int dimensionX, - int dimensionY) throws NotFoundException { - - GridSampler sampler = GridSampler.getInstance(); - - return sampler.sampleGrid(image, - dimensionX, - dimensionY, - 0.5f, - 0.5f, - dimensionX - 0.5f, - 0.5f, - dimensionX - 0.5f, - dimensionY - 0.5f, - 0.5f, - dimensionY - 0.5f, - topLeft.getX(), - topLeft.getY(), - topRight.getX(), - topRight.getY(), - bottomRight.getX(), - bottomRight.getY(), - bottomLeft.getX(), - bottomLeft.getY()); - } - - /** - * Counts the number of black/white transitions between two points, using something like Bresenham's algorithm. - */ - private int transitionsBetween(RXingResultPoint from, RXingResultPoint to) { - // See QR Code Detector, sizeOfBlackWhiteBlackRun() - int fromX = (int) from.getX(); - int fromY = (int) from.getY(); - int toX = (int) to.getX(); - int toY = Math.min(image.getHeight() - 1, (int) to.getY()); - - boolean steep = Math.abs(toY - fromY) > Math.abs(toX - fromX); - if (steep) { - int temp = fromX; - fromX = fromY; - fromY = temp; - temp = toX; - toX = toY; - toY = temp; - } - - int dx = Math.abs(toX - fromX); - int dy = Math.abs(toY - fromY); - int error = -dx / 2; - int ystep = fromY < toY ? 1 : -1; - int xstep = fromX < toX ? 1 : -1; - int transitions = 0; - boolean inBlack = image.get(steep ? fromY : fromX, steep ? fromX : fromY); - for (int x = fromX, y = fromY; x != toX; x += xstep) { - boolean isBlack = image.get(steep ? y : x, steep ? x : y); - if (isBlack != inBlack) { - transitions++; - inBlack = isBlack; - } - error += dy; - if (error > 0) { - if (y == toY) { - break; - } - y += ystep; - error -= dx; - } - } - return transitions; - } - -} diff --git a/src/datamatrix/detector/datamatrix_result.rs b/src/datamatrix/detector/datamatrix_result.rs new file mode 100644 index 0000000..caeea5b --- /dev/null +++ b/src/datamatrix/detector/datamatrix_result.rs @@ -0,0 +1,19 @@ +use crate::{common::{DetectorRXingResult, BitMatrix}, RXingResultPoint}; + +pub struct DatamatrixDetectorResult(BitMatrix,Vec); + +impl DatamatrixDetectorResult { + pub fn new(bits:BitMatrix, points:Vec)->Self { + Self(bits,points) + } +} + +impl DetectorRXingResult for DatamatrixDetectorResult { + fn getBits(&self) -> &BitMatrix { + &self.0 + } + + fn getPoints(&self) -> &Vec { + &self.1 + } +} \ No newline at end of file diff --git a/src/datamatrix/detector/detector.rs b/src/datamatrix/detector/detector.rs new file mode 100644 index 0000000..dcda141 --- /dev/null +++ b/src/datamatrix/detector/detector.rs @@ -0,0 +1,413 @@ +/* + * Copyright 2008 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +use crate::{ + common::{detector::WhiteRectangleDetector, BitMatrix, DefaultGridSampler, GridSampler}, + Exceptions, RXingResultPoint, ResultPoint, +}; + +use super::DatamatrixDetectorResult; + +/** + *

Encapsulates logic that can detect a Data Matrix Code in an image, even if the Data Matrix Code + * is rotated or skewed, or partially obscured.

+ * + * @author Sean Owen + */ +pub struct Detector { + image: BitMatrix, + rectangleDetector: WhiteRectangleDetector, +} +impl Detector { + pub fn new(image: BitMatrix) -> Result { + Ok(Self { + rectangleDetector: WhiteRectangleDetector::new_from_image(&image)?, + image, + }) + } + + /** + *

Detects a Data Matrix Code in an image.

+ * + * @return {@link DetectorRXingResult} encapsulating results of detecting a Data Matrix Code + * @throws NotFoundException if no Data Matrix Code can be found + */ + pub fn detect(&self) -> Result { + let cornerPoints = self.rectangleDetector.detect()?; + + let mut points = self.detectSolid1(&cornerPoints); + points = self.detectSolid2(&points); + if let Some(point) = self.correctTopRight(&points) { + points[3] = point; + } else { + return Err(Exceptions::NotFoundException("point 4 unfound".to_owned())); + } + // points[3] = self.correctTopRight(&points); + // if points[3] == null { + // throw NotFoundException.getNotFoundInstance(); + // } + points = self.shiftToModuleCenter(&points); + + let topLeft = points[0]; + let bottomLeft = points[1]; + let bottomRight = points[2]; + let topRight = points[3]; + + let mut dimensionTop = self.transitionsBetween(&topLeft, &topRight) + 1; + let mut dimensionRight = self.transitionsBetween(&bottomRight, &topRight) + 1; + if (dimensionTop & 0x01) == 1 { + dimensionTop += 1; + } + if (dimensionRight & 0x01) == 1 { + dimensionRight += 1; + } + + if 4 * dimensionTop < 6 * dimensionRight && 4 * dimensionRight < 6 * dimensionTop { + // The matrix is square + dimensionTop = dimensionTop.max(dimensionRight); + dimensionRight = dimensionTop.max(dimensionRight); + } + + let bits = Self::sampleGrid( + &self.image, + &topLeft, + &bottomLeft, + &bottomRight, + &topRight, + dimensionTop, + dimensionRight, + )?; + + Ok(DatamatrixDetectorResult::new( + bits, + vec![topLeft, bottomLeft, bottomRight, topRight], + )) + } + + fn shiftPoint(point: RXingResultPoint, to: RXingResultPoint, div: u32) -> RXingResultPoint { + let x = (to.getX() - point.getX()) / (div as f32 + 1.0); + let y = (to.getY() - point.getY()) / (div as f32 + 1.0); + RXingResultPoint::new(point.getX() + x, point.getY() + y) + } + + fn moveAway(point: RXingResultPoint, fromX: f32, fromY: f32) -> RXingResultPoint { + let mut x = point.getX(); + let mut y = point.getY(); + + if x < fromX { + x -= 1.0; + } else { + x += 1.0; + } + + if y < fromY { + y -= 1.0; + } else { + y += 1.0; + } + + RXingResultPoint::new(x, y) + } + + /** + * Detect a solid side which has minimum transition. + */ + fn detectSolid1(&self, cornerPoints: &[RXingResultPoint]) -> [RXingResultPoint; 4] { + // 0 2 + // 1 3 + let pointA = cornerPoints[0]; + let pointB = cornerPoints[1]; + let pointC = cornerPoints[3]; + let pointD = cornerPoints[2]; + + let trAB = self.transitionsBetween(&pointA, &pointB); + let trBC = self.transitionsBetween(&pointB, &pointC); + let trCD = self.transitionsBetween(&pointC, &pointD); + let trDA = self.transitionsBetween(&pointD, &pointA); + + // 0..3 + // : : + // 1--2 + let mut min = trAB; + let mut points = [pointD, pointA, pointB, pointC]; + if min > trBC { + min = trBC; + points[0] = pointA; + points[1] = pointB; + points[2] = pointC; + points[3] = pointD; + } + if min > trCD { + min = trCD; + points[0] = pointB; + points[1] = pointC; + points[2] = pointD; + points[3] = pointA; + } + if min > trDA { + points[0] = pointC; + points[1] = pointD; + points[2] = pointA; + points[3] = pointB; + } + + points + } + + /** + * Detect a second solid side next to first solid side. + */ + fn detectSolid2(&self, points: &[RXingResultPoint]) -> [RXingResultPoint; 4] { + // A..D + // : : + // B--C + let pointA = points[0]; + let pointB = points[1]; + let pointC = points[2]; + let pointD = points[3]; + + // Transition detection on the edge is not stable. + // To safely detect, shift the points to the module center. + let tr = self.transitionsBetween(&pointA, &pointD); + let pointBs = Self::shiftPoint(pointB, pointC, (tr + 1) * 4); + let pointCs = Self::shiftPoint(pointC, pointB, (tr + 1) * 4); + let trBA = self.transitionsBetween(&pointBs, &pointA); + let trCD = self.transitionsBetween(&pointCs, &pointD); + + // 0..3 + // | : + // 1--2 + if trBA < trCD { + // solid sides: A-B-C + [pointA, pointB, pointC, pointD] + // points[0] = pointA; + // points[1] = pointB; + // points[2] = pointC; + // points[3] = pointD; + } else { + // solid sides: B-C-D + [pointB, pointC, pointD, pointA] + // points[0] = pointB; + // points[1] = pointC; + // points[2] = pointD; + // points[3] = pointA; + } + } + + /** + * Calculates the corner position of the white top right module. + */ + fn correctTopRight(&self, points: &[RXingResultPoint]) -> Option { + // A..D + // | : + // B--C + let pointA = points[0]; + let pointB = points[1]; + let pointC = points[2]; + let pointD = points[3]; + + // shift points for safe transition detection. + let mut trTop = self.transitionsBetween(&pointA, &pointD); + let mut trRight = self.transitionsBetween(&pointB, &pointD); + let pointAs = Self::shiftPoint(pointA, pointB, (trRight + 1) * 4); + let pointCs = Self::shiftPoint(pointC, pointB, (trTop + 1) * 4); + + trTop = self.transitionsBetween(&pointAs, &pointD); + trRight = self.transitionsBetween(&pointCs, &pointD); + + let candidate1 = RXingResultPoint::new( + pointD.getX() + (pointC.getX() - pointB.getX()) / (trTop as f32 + 1.0), + pointD.getY() + (pointC.getY() - pointB.getY()) / (trTop as f32 + 1.0), + ); + let candidate2 = RXingResultPoint::new( + pointD.getX() + (pointA.getX() - pointB.getX()) / (trRight as f32 + 1.0), + pointD.getY() + (pointA.getY() - pointB.getY()) / (trRight as f32 + 1.0), + ); + + if !self.isValid(&candidate1) { + if self.isValid(&candidate2) { + return Some(candidate2); + } + return None; + } + if !self.isValid(&candidate2) { + return Some(candidate1); + } + + let sumc1 = self.transitionsBetween(&pointAs, &candidate1) + + self.transitionsBetween(&pointCs, &candidate1); + let sumc2 = self.transitionsBetween(&pointAs, &candidate2) + + self.transitionsBetween(&pointCs, &candidate2); + + if sumc1 > sumc2 { + return Some(candidate1); + } else { + return Some(candidate2); + } + } + + /** + * Shift the edge points to the module center. + */ + fn shiftToModuleCenter(&self, points: &[RXingResultPoint]) -> [RXingResultPoint; 4] { + // A..D + // | : + // B--C + let mut pointA = points[0]; + let mut pointB = points[1]; + let mut pointC = points[2]; + let mut pointD = points[3]; + + // calculate pseudo dimensions + let mut dimH = self.transitionsBetween(&pointA, &pointD) + 1; + let mut dimV = self.transitionsBetween(&pointC, &pointD) + 1; + + // shift points for safe dimension detection + let mut pointAs = Self::shiftPoint(pointA, pointB, dimV * 4); + let mut pointCs = Self::shiftPoint(pointC, pointB, dimH * 4); + + // calculate more precise dimensions + dimH = self.transitionsBetween(&pointAs, &pointD) + 1; + dimV = self.transitionsBetween(&pointCs, &pointD) + 1; + if (dimH & 0x01) == 1 { + dimH += 1; + } + if (dimV & 0x01) == 1 { + dimV += 1; + } + + // WhiteRectangleDetector returns points inside of the rectangle. + // I want points on the edges. + let centerX = (pointA.getX() + pointB.getX() + pointC.getX() + pointD.getX()) / 4.0; + let centerY = (pointA.getY() + pointB.getY() + pointC.getY() + pointD.getY()) / 4.0; + pointA = Self::moveAway(pointA, centerX, centerY); + pointB = Self::moveAway(pointB, centerX, centerY); + pointC = Self::moveAway(pointC, centerX, centerY); + pointD = Self::moveAway(pointD, centerX, centerY); + + let mut pointBs; + let mut pointDs; + + // shift points to the center of each modules + pointAs = Self::shiftPoint(pointA, pointB, dimV * 4); + pointAs = Self::shiftPoint(pointAs, pointD, dimH * 4); + pointBs = Self::shiftPoint(pointB, pointA, dimV * 4); + pointBs = Self::shiftPoint(pointBs, pointC, dimH * 4); + pointCs = Self::shiftPoint(pointC, pointD, dimV * 4); + pointCs = Self::shiftPoint(pointCs, pointB, dimH * 4); + pointDs = Self::shiftPoint(pointD, pointC, dimV * 4); + pointDs = Self::shiftPoint(pointDs, pointA, dimH * 4); + + [pointAs, pointBs, pointCs, pointDs] + } + + fn isValid(&self, p: &RXingResultPoint) -> bool { + return p.getX() >= 0.0 + && p.getX() <= self.image.getWidth() as f32 - 1.0 + && p.getY() > 0.0 + && p.getY() <= self.image.getHeight() as f32 - 1.0; + } + + fn sampleGrid( + image: &BitMatrix, + topLeft: &RXingResultPoint, + bottomLeft: &RXingResultPoint, + bottomRight: &RXingResultPoint, + topRight: &RXingResultPoint, + dimensionX: u32, + dimensionY: u32, + ) -> Result { + let sampler = DefaultGridSampler {}; + + return sampler.sample_grid_detailed( + image, + dimensionX, + dimensionY, + 0.5, + 0.5, + dimensionX as f32 - 0.5, + 0.5, + dimensionX as f32 - 0.5, + dimensionY as f32 - 0.5, + 0.5, + dimensionY as f32 - 0.5, + topLeft.getX(), + topLeft.getY(), + topRight.getX(), + topRight.getY(), + bottomRight.getX(), + bottomRight.getY(), + bottomLeft.getX(), + bottomLeft.getY(), + ); + } + + /** + * Counts the number of black/white transitions between two points, using something like Bresenham's algorithm. + */ + fn transitionsBetween(&self, from: &RXingResultPoint, to: &RXingResultPoint) -> u32 { + // See QR Code Detector, sizeOfBlackWhiteBlackRun() + let mut fromX = from.getX().floor() as i32; + let mut fromY = from.getY().floor() as i32; + let mut toX = to.getX().floor() as i32; + let mut toY = (self.image.getHeight() - 1).min(to.getY().floor() as u32) as i32; + + let steep = (toY - fromY).abs() > (toX - fromX).abs(); + if steep { + let mut temp = fromX; + fromX = fromY; + fromY = temp; + temp = toX; + toX = toY; + toY = temp; + } + + let dx = (toX - fromX).abs(); + let dy = (toY - fromY).abs(); + let mut error = -dx / 2; + let ystep = if fromY < toY { 1 } else { -1 }; + let xstep = if fromX < toX { 1 } else { -1 }; + let mut transitions = 0; + let mut inBlack = self.image.get( + if steep { fromY as u32 } else { fromX as u32 }, + if steep { fromX as u32 } else { fromY as u32 }, + ); + let mut x = fromX; + let mut y = fromY; + while x != toX { + // for (int x = fromX, y = fromY; x != toX; x += xstep) { + let isBlack = self.image.get( + if steep { y as u32 } else { x as u32 }, + if steep { x as u32 } else { y as u32 }, + ); + if isBlack != inBlack { + transitions += 1; + inBlack = isBlack; + } + error += dy; + if error > 0 { + if y == toY { + break; + } + y += ystep; + error -= dx; + } + + x += xstep; + } + return transitions; + } +} diff --git a/src/datamatrix/detector/mod.rs b/src/datamatrix/detector/mod.rs index e69de29..fdb8a18 100644 --- a/src/datamatrix/detector/mod.rs +++ b/src/datamatrix/detector/mod.rs @@ -0,0 +1,4 @@ +mod detector; +mod datamatrix_result; +pub use detector::*; +pub use datamatrix_result::*; \ No newline at end of file