/* * Copyright 2007 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; // import java.util.Arrays; use std::fmt; use crate::Exceptions; use super::BitArray; /** *
Represents a 2D matrix of bits. In function arguments below, and throughout the common * module, x is the column position, and y is the row position. The ordering is always x, y. * The origin is at the top-left.
* *Internally the bits are represented in a 1-D array of 32-bit ints. However, each row begins * with a new int. This is done intentionally so that we can copy out a row into a BitArray very * efficiently.
* *The ordering of bits is row-major. Within each int, the least significant bits are used first, * meaning they represent lower x values. This is compatible with BitArray's implementation.
* * @author Sean Owen * @author dswitkin@google.com (Daniel Switkin) */ #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct BitMatrix { width: u32, height: u32, row_size: usize, bits: VecGets the requested bit, where true means black.
* * @param x The horizontal component (i.e. which column) * @param y The vertical component (i.e. which row) * @return value of given bit in matrix */ pub fn get(&self, x: u32, y: u32) -> bool { let offset = self.get_offset(y, x); ((self.bits[offset] >> (x & 0x1f)) & 1) != 0 } #[inline(always)] fn get_offset(&self, y: u32, x: u32) -> usize { y as usize * self.row_size + (x as usize / 32) } pub fn try_get(&self, x: u32, y: u32) -> ResultSets the given bit to true.
* * @param x The horizontal component (i.e. which column) * @param y The vertical component (i.e. which row) */ pub fn set(&mut self, x: u32, y: u32) { let offset = self.get_offset(y, x); self.bits[offset] |= 1 << (x & 0x1f); } pub fn unset(&mut self, x: u32, y: u32) { let offset = self.get_offset(y, x); self.bits[offset] &= !(1 << (x & 0x1f)); } /** *Flips the given bit.
* * @param x The horizontal component (i.e. which column) * @param y The vertical component (i.e. which row) */ pub fn flip_coords(&mut self, x: u32, y: u32) { let offset = self.get_offset(y, x); self.bits[offset] ^= 1 << (x & 0x1f); } /** *Flips every bit in the matrix.
*/ pub fn flip_self(&mut self) { let max = self.bits.len(); for bit_set in self.bits.iter_mut().take(max) { *bit_set = !*bit_set; } } /** * Exclusive-or (XOR): Flip the bit in this {@code BitMatrix} if the corresponding * mask bit is set. * * @param mask XOR mask */ pub fn xor(&mut self, mask: &BitMatrix) -> Result<(), Exceptions> { if self.width != mask.width || self.height != mask.height || self.row_size != mask.row_size { return Err(Exceptions::IllegalArgumentException(Some( "input matrix dimensions do not match".to_owned(), ))); } // let mut rowArray = BitArray::with_size(self.width as usize); for y in 0..self.height { //for (int y = 0; y < height; y++) { let offset = y as usize * self.row_size; let rowArray = mask.getRow(y); let row = rowArray.getBitArray(); for (x, row_x) in row.iter().enumerate().take(self.row_size) { // for x in 0..self.row_size { //for (int x = 0; x < rowSize; x++) { self.bits[offset + x] ^= *row_x; } } Ok(()) } /** * Clears all bits (sets to false). */ pub fn clear(&mut self) { // let max = self.bits.len(); // for i in 0..max { // //for (int i = 0; i < max; i++) { // self.bits[i] = 0; // } self.bits.fill(0); } /** *Sets a square region of the bit matrix to true.
* * @param left The horizontal position to begin at (inclusive) * @param top The vertical position to begin at (inclusive) * @param width The width of the region * @param height The height of the region */ pub fn setRegion( &mut self, left: u32, top: u32, width: u32, height: u32, ) -> Result<(), Exceptions> { // if top < 0 || left < 0 { // return Err(Exceptions::IllegalArgumentException( // "Left and top must be nonnegative".to_owned(), // )); // } if height < 1 || width < 1 { return Err(Exceptions::IllegalArgumentException(Some( "height and width must be at least 1".to_owned(), ))); } let right = left + width; let bottom = top + height; if bottom > self.height || right > self.width { return Err(Exceptions::IllegalArgumentException(Some( "the region must fit inside the matrix".to_owned(), ))); } for y in top..bottom { //for (int y = top; y < bottom; y++) { let offset = y as usize * self.row_size; for x in left..right { //for (int x = left; x < right; x++) { self.bits[offset + (x as usize / 32)] |= 1 << (x & 0x1f); } } Ok(()) } /** * A fast method to retrieve one row of data from the matrix as a BitArray. * * @param y The row to retrieve * @param row An optional caller-allocated BitArray, will be allocated if null or too small * @return The resulting BitArray - this reference should always be used even when passing * your own row */ pub fn getRow(&self, y: u32) -> BitArray { // let mut rw: BitArray = if row.getSize() < self.width as usize { // BitArray::with_size(self.width as usize) // } else { // let mut z = row; //row.clone(); // z.clear(); // z // // row.clear(); // // row.clone() // }; let mut rw = BitArray::with_size(self.width as usize); let offset = y as usize * self.row_size; for x in 0..self.row_size { //for (int x = 0; x < rowSize; x++) { rw.setBulk(x * 32, self.bits[offset + x]); } rw } /** * @param y row to set * @param row {@link BitArray} to copy from */ pub fn setRow(&mut self, y: u32, row: &BitArray) { self.bits[y as usize * self.row_size..y as usize * self.row_size + self.row_size] .clone_from_slice(&row.getBitArray()[0..self.row_size]) //System.arraycopy(row.getBitArray(), 0, self.bits, y * self.rowSize, self.rowSize); } /** * Modifies this {@code BitMatrix} to represent the same but rotated the given degrees (0, 90, 180, 270) * * @param degrees number of degrees to rotate through counter-clockwise (0, 90, 180, 270) */ pub fn rotate(&mut self, degrees: u32) -> Result<(), Exceptions> { match degrees % 360 { 0 => Ok(()), 90 => { self.rotate90(); Ok(()) } 180 => { self.rotate180(); Ok(()) } 270 => { self.rotate90(); self.rotate180(); Ok(()) } _ => Err(Exceptions::IllegalArgumentException(Some( "degrees must be a multiple of 0, 90, 180, or 270".to_owned(), ))), } } /** * Modifies this {@code BitMatrix} to represent the same but rotated 180 degrees */ pub fn rotate180(&mut self) { // let mut topRow = BitArray::with_size(self.width as usize); // let mut bottomRow = BitArray::with_size(self.width as usize); let maxHeight = (self.height + 1) / 2; for i in 0..maxHeight { //for (int i = 0; i < maxHeight; i++) { let mut topRow = self.getRow(i); let bottomRowIndex = self.height - 1 - i; let mut bottomRow = self.getRow(bottomRowIndex); topRow.reverse(); bottomRow.reverse(); self.setRow(i, &bottomRow); self.setRow(bottomRowIndex, &topRow); } } /** * Modifies this {@code BitMatrix} to represent the same but rotated 90 degrees counterclockwise */ pub fn rotate90(&mut self) { let newWidth = self.height; let newHeight = self.width; let newRowSize = (newWidth + 31) / 32; let mut newBits = vec![0; (newRowSize * newHeight) as usize]; for y in 0..self.height { //for (int y = 0; y < height; y++) { for x in 0..self.width { //for (int x = 0; x < width; x++) { let offset = self.get_offset(y, x); if ((self.bits[offset] >> (x & 0x1f)) & 1) != 0 { let newOffset: usize = ((newHeight - 1 - x) * newRowSize + (y / 32)) as usize; newBits[newOffset] |= 1 << (y & 0x1f); } } } self.width = newWidth; self.height = newHeight; self.row_size = newRowSize as usize; self.bits = newBits; } /** * This is useful in detecting the enclosing rectangle of a 'pure' barcode. * * @return {@code left,top,width,height} enclosing rectangle of all 1 bits, or null if it is all white */ pub fn getEnclosingRectangle(&self) -> Option<[u32; 4]> { let mut left = self.width; let mut top = self.height; // let right = -1; // let bottom = -1; let mut right: u32 = 0; let mut bottom = 0; for y in 0..self.height { //for (int y = 0; y < height; y++) { for x32 in 0..self.row_size { //for (int x32 = 0; x32 < rowSize; x32++) { let theBits = self.bits[y as usize * self.row_size + x32]; if theBits != 0 { if y < top { top = y; } if y > bottom { bottom = y; } if x32 * 32 < left as usize { let mut bit = 0; while (theBits << (31 - bit)) == 0 { bit += 1; } if (x32 * 32 + bit) < left as usize { left = (x32 * 32 + bit) as u32; } } if x32 * 32 + 31 > right as usize { let mut bit = 31; while (theBits >> bit) == 0 { bit -= 1; } if (x32 * 32 + bit) > right as usize { right = (x32 * 32 + bit) as u32; } } } } } if right < left || bottom < top { return None; } Some([left, top, right - left + 1, bottom - top + 1]) } /** * This is useful in detecting a corner of a 'pure' barcode. * * @return {@code x,y} coordinate of top-left-most 1 bit, or null if it is all white */ pub fn getTopLeftOnBit(&self) -> Option