/* * Copyright 2010 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.common.detector; use crate::{NotFoundException,RXingResultPoint}; use crate::common::BitMatrix; /** *

* Detects a candidate barcode-like rectangular region within an image. It * starts around the center of the image, increases the size of the candidate * region until it finds a white rectangular region. By keeping track of the * last black points it encountered, it determines the corners of the barcode. *

* * @author David Olivier */ const INIT_SIZE:i32 = 10; const CORR:i32 = 1; pub struct WhiteRectangleDetector { image: BitMatrix, height: i32, width: i32, leftInit: i32, rightInit: i32, downInit: i32, upInit: i32, } impl WhiteRectangleDetector { pub fn new_from_image(image:&BitMatrix) -> Result { Self::new(image, INIT_SIZE, image.getWidth() / 2, image.getHeight() / 2); } /** * @param image barcode image to find a rectangle in * @param initSize initial size of search area around center * @param x x position of search center * @param y y position of search center * @throws NotFoundException if image is too small to accommodate {@code initSize} */ pub fn new( image:&BitMatrix, initSize:i32, x:i32, y:i32) -> Result { let new_wrd : Self; new_wrd.image = image; new_wrd.height = image.getHeight(); new_wrd.width = image.getWidth(); let halfsize = initSize / 2; new_wrd.leftInit = x - halfsize; new_wrd.rightInit = x + halfsize; new_wrd.upInit = y - halfsize; new_wrd.downInit = y + halfsize; if (upInit < 0 || leftInit < 0 || downInit >= height || rightInit >= width) { return Err( NotFoundException.getNotFoundInstance()); } Ok(new_wrd) } /** *

* Detects a candidate barcode-like rectangular region within an image. It * starts around the center of the image, increases the size of the candidate * region until it finds a white rectangular region. *

* * @return {@link RXingResultPoint}[] describing the corners of the rectangular * region. The first and last points are opposed on the diagonal, as * are the second and third. The first point will be the topmost * point and the last, the bottommost. The second point will be * leftmost and the third, the rightmost * @throws NotFoundException if no Data Matrix Code can be found */ pub fn detect() -> Result, NotFoundException> { let left :i32= leftInit; let right:i32 = rightInit; let up:i32 = upInit; let down:i32 = downInit; let sizeExceeded = false; let aBlackPointFoundOnBorder = true; let atLeastOneBlackPointFoundOnRight = false; let atLeastOneBlackPointFoundOnBottom = false; let atLeastOneBlackPointFoundOnLeft = false; let atLeastOneBlackPointFoundOnTop = false; while (aBlackPointFoundOnBorder) { aBlackPointFoundOnBorder = false; // ..... // . | // ..... let rightBorderNotWhite = true; while ((rightBorderNotWhite || !atLeastOneBlackPointFoundOnRight) && right < width) { rightBorderNotWhite = containsBlackPoint(up, down, right, false); if (rightBorderNotWhite) { right += 1; aBlackPointFoundOnBorder = true; atLeastOneBlackPointFoundOnRight = true; } else if (!atLeastOneBlackPointFoundOnRight) { right+=1; } } if (right >= width) { sizeExceeded = true; break; } // ..... // . . // .___. let bottomBorderNotWhite = true; while ((bottomBorderNotWhite || !atLeastOneBlackPointFoundOnBottom) && down < height) { bottomBorderNotWhite = containsBlackPoint(left, right, down, true); if (bottomBorderNotWhite) { down+=1; aBlackPointFoundOnBorder = true; atLeastOneBlackPointFoundOnBottom = true; } else if (!atLeastOneBlackPointFoundOnBottom) { down+=1; } } if (down >= height) { sizeExceeded = true; break; } // ..... // | . // ..... let leftBorderNotWhite = true; while ((leftBorderNotWhite || !atLeastOneBlackPointFoundOnLeft) && left >= 0) { leftBorderNotWhite = containsBlackPoint(up, down, left, false); if (leftBorderNotWhite) { left-=1; aBlackPointFoundOnBorder = true; atLeastOneBlackPointFoundOnLeft = true; } else if (!atLeastOneBlackPointFoundOnLeft) { left-=1; } } if (left < 0) { sizeExceeded = true; break; } // .___. // . . // ..... let topBorderNotWhite = true; while ((topBorderNotWhite || !atLeastOneBlackPointFoundOnTop) && up >= 0) { topBorderNotWhite = containsBlackPoint(left, right, up, true); if (topBorderNotWhite) { up-=1; aBlackPointFoundOnBorder = true; atLeastOneBlackPointFoundOnTop = true; } else if (!atLeastOneBlackPointFoundOnTop) { up-=1; } } if (up < 0) { sizeExceeded = true; break; } } if (!sizeExceeded) { let maxSize = right - left; let mut z: Option = None; let mut i = 1; while z.is_none() && i < maxSize { //for (int i = 1; z == null && i < maxSize; i++) { z = getBlackPointOnSegment(left, down - i, left + i, down); i+=1; } if (z .is_none()) { return Err( NotFoundException.getNotFoundInstance()); } let mut t : Option = None; //go down right let mut i = 1; while t.is_none() && i < maxSize { //for (int i = 1; t == null && i < maxSize; i++) { t = getBlackPointOnSegment(left, up + i, left + i, up); i+=1; } if (t .is_none()) { return Err( NotFoundException.getNotFoundInstance()); } let mut x : Option = None; //go down left let mut i = 1; while x.is_none() && i < maxSize { //for (int i = 1; x == null && i < maxSize; i++) { x = getBlackPointOnSegment(right, up + i, right - i, up); i += 1; } if (x .is_none()) { return Err( NotFoundException.getNotFoundInstance()); } let mut y : Option = None; //go up left let mut i = 1; while y.is_none() && i < maxSize { //for (int i = 1; y == null && i < maxSize; i++) { y = getBlackPointOnSegment(right, down - i, right - i, down); i+=1; } if (y .is_none()) { return Err( NotFoundException.getNotFoundInstance()); } return centerEdges(y, z, x, t); } else { return Err( NotFoundException.getNotFoundInstance()); } } fn getBlackPointOnSegment( aX:f32, aY:f32, bX:f32, bY:f32) -> Option { let dist = MathUtils.round(MathUtils.distance(aX, aY, bX, bY)); let xStep :f32= (bX - aX) / dist; let yStep:f32 = (bY - aY) / dist; for i in 0..dist { let x = MathUtils.round(aX + i * xStep); let y = MathUtils.round(aY + i * yStep); if (image.get(x, y)) { return RXingResultPoint::new(x, y); } } return None; } /** * recenters the points of a constant distance towards the center * * @param y bottom most point * @param z left most point * @param x right most point * @param t top most point * @return {@link RXingResultPoint}[] describing the corners of the rectangular * region. The first and last points are opposed on the diagonal, as * are the second and third. The first point will be the topmost * point and the last, the bottommost. The second point will be * leftmost and the third, the rightmost */ fn centerEdges( y:&RXingResultPoint, z:&RXingResultPoint, x:&RXingResultPoint, t:&RXingResultPoint) -> Vec { // // t t // z x // x OR z // y y // let yi = y.getX(); let yj = y.getY(); let zi = z.getX(); let zj = z.getY(); let xi = x.getX(); let xj = x.getY(); let ti = t.getX(); let tj = t.getY(); if (yi < width / 2.0f) { return Vec! [ RXingResultPoint::new(ti - CORR, tj + CORR), RXingResultPoint::new(zi + CORR, zj + CORR), RXingResultPoint::new(xi - CORR, xj - CORR), RXingResultPoint::new(yi + CORR, yj - CORR)]; } else { return Vec![ RXingResultPoint::new(ti + CORR, tj + CORR), RXingResultPoint::new(zi + CORR, zj - CORR), RXingResultPoint::new(xi - CORR, xj + CORR), RXingResultPoint::new(yi - CORR, yj - CORR)]; } } /** * Determines whether a segment contains a black point * * @param a min value of the scanned coordinate * @param b max value of the scanned coordinate * @param fixed value of fixed coordinate * @param horizontal set to true if scan must be horizontal, false if vertical * @return true if a black point has been found, else false. */ fn containsBlackPoint( a:i32, b:i32, fixed:i32, horizontal:bool) -> bool { if (horizontal) { for x in a..=b { if (image.get(x, fixed)) { return true; } } } else { for y in a..=b { if (image.get(fixed, y)) { return true; } } } return false; } }