pub mod detector; pub mod reedsolomon; use std::cmp; use std::fmt; use std::{any::Any, collections::HashMap}; use crate::exceptions::IllegalArgumentException; use crate::DecodeHintType; use crate::RXingResultPoint; use encoding::Encoding; /* * Copyright (C) 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; // import java.nio.charset.Charset; // import java.nio.charset.StandardCharsets; // import java.util.Map; /** * Common string-related functions. * * @author Sean Owen * @author Alex Dupre */ pub struct StringUtils { // private static final Charset PLATFORM_DEFAULT_ENCODING = Charset.defaultCharset(); // public static final Charset SHIFT_JIS_CHARSET = Charset.forName("SJIS"); // public static final Charset GB2312_CHARSET = Charset.forName("GB2312"); // private static final Charset EUC_JP = Charset.forName("EUC_JP"); // private static final boolean ASSUME_SHIFT_JIS = // SHIFT_JIS_CHARSET.equals(PLATFORM_DEFAULT_ENCODING) || // EUC_JP.equals(PLATFORM_DEFAULT_ENCODING); // // Retained for ABI compatibility with earlier versions // public static final String SHIFT_JIS = "SJIS"; // public static final String GB2312 = "GB2312"; } const PLATFORM_DEFAULT_ENCODING: dyn Encoding = encoding::all::UTF_8; const SHIFT_JIS_CHARSET: dyn Encoding = encoding::label::encoding_from_whatwg_label("SJIS"); const GB2312_CHARSET: dyn Encoding = encoding::label::encoding_from_whatwg_label("GB2312"); const EUC_JP: dyn Encoding = encoding::label::encoding_from_whatwg_label("EUC_JP"); const ASSUME_SHIFT_JIS: bool = false; static SHIFT_JIS: &'static str = "SJIS"; static GB2312: &'static str = "GB2312"; // private static final boolean ASSUME_SHIFT_JIS = // SHIFT_JIS_CHARSET.equals(PLATFORM_DEFAULT_ENCODING) || // EUC_JP.equals(PLATFORM_DEFAULT_ENCODING); impl StringUtils { /** * @param bytes bytes encoding a string, whose encoding should be guessed * @param hints decode hints if applicable * @return name of guessed encoding; at the moment will only guess one of: * "SJIS", "UTF8", "ISO8859_1", or the platform default encoding if none * of these can possibly be correct */ pub fn guessEncoding(bytes: &[u8], hints: HashMap) -> &str { let c = StringUtils::guessCharset(bytes, hints); if c == SHIFT_JIS_CHARSET { return "SJIS"; } else if c == encoding::all::UTF_8 { return "UTF8"; } else if c == encoding::all::ISO_8859_1 { return "ISO8859_1"; } return c.name(); } /** * @param bytes bytes encoding a string, whose encoding should be guessed * @param hints decode hints if applicable * @return Charset of guessed encoding; at the moment will only guess one of: * {@link #SHIFT_JIS_CHARSET}, {@link StandardCharsets#UTF_8}, * {@link StandardCharsets#ISO_8859_1}, {@link StandardCharsets#UTF_16}, * or the platform default encoding if * none of these can possibly be correct */ pub fn guessCharset( bytes: &[u8], hints: HashMap, ) -> Box<&dyn Encoding> { match hints.get(&DecodeHintType::CHARACTER_SET) { Some(hint) => { if hint.is::() { return encoding::label::encoding_from_whatwg_label(hint).unwrap(); } } _ => {} }; // if hints.contains_key(&DecodeHintType::CHARACTER_SET) { // return Charset.forName(hints.get(DecodeHintType.CHARACTER_SET).toString()); // } // First try UTF-16, assuming anything with its BOM is UTF-16 if bytes.len() > 2 && ((bytes[0] == 0xFE && bytes[1] == 0xFF) || (bytes[0] == 0xFF && bytes[1] == 0xFE)) { return encoding::all::UTF_16BE; } // For now, merely tries to distinguish ISO-8859-1, UTF-8 and Shift_JIS, // which should be by far the most common encodings. let length = bytes.len(); let canBeISO88591 = true; let canBeShiftJIS = true; let canBeUTF8 = true; let utf8BytesLeft = 0; let utf2BytesChars = 0; let utf3BytesChars = 0; let utf4BytesChars = 0; let sjisBytesLeft = 0; let sjisKatakanaChars = 0; let sjisCurKatakanaWordLength = 0; let sjisCurDoubleBytesWordLength = 0; let sjisMaxKatakanaWordLength = 0; let sjisMaxDoubleBytesWordLength = 0; let isoHighOther = 0; let utf8bom = bytes.len() > 3 && bytes[0] == 0xEF && bytes[1] == 0xBB && bytes[2] == 0xBF; for i in 0..length { // for (int i = 0; // i < length && (canBeISO88591 || canBeShiftJIS || canBeUTF8); // i++) { if canBeISO88591 || canBeShiftJIS || canBeUTF8 { break; } let value = bytes[i] & 0xFF; // UTF-8 stuff if canBeUTF8 { if utf8BytesLeft > 0 { if (value & 0x80) == 0 { canBeUTF8 = false; } else { utf8BytesLeft -= 1; } } else if (value & 0x80) != 0 { if (value & 0x40) == 0 { canBeUTF8 = false; } else { utf8BytesLeft += 1; if (value & 0x20) == 0 { utf2BytesChars += 1; } else { utf8BytesLeft += 1; if (value & 0x10) == 0 { utf3BytesChars += 1; } else { utf8BytesLeft += 1; if (value & 0x08) == 0 { utf4BytesChars += 1; } else { canBeUTF8 = false; } } } } } } // ISO-8859-1 stuff if canBeISO88591 { if value > 0x7F && value < 0xA0 { canBeISO88591 = false; } else if value > 0x9F && (value < 0xC0 || value == 0xD7 || value == 0xF7) { isoHighOther += 1; } } // Shift_JIS stuff if canBeShiftJIS { if sjisBytesLeft > 0 { if value < 0x40 || value == 0x7F || value > 0xFC { canBeShiftJIS = false; } else { sjisBytesLeft -= 1; } } else if value == 0x80 || value == 0xA0 || value > 0xEF { canBeShiftJIS = false; } else if value > 0xA0 && value < 0xE0 { sjisKatakanaChars += 1; sjisCurDoubleBytesWordLength = 0; sjisCurKatakanaWordLength += 1; if sjisCurKatakanaWordLength > sjisMaxKatakanaWordLength { sjisMaxKatakanaWordLength = sjisCurKatakanaWordLength; } } else if value > 0x7F { sjisBytesLeft += 1; //sjisDoubleBytesChars++; sjisCurKatakanaWordLength = 0; sjisCurDoubleBytesWordLength += 1; if sjisCurDoubleBytesWordLength > sjisMaxDoubleBytesWordLength { sjisMaxDoubleBytesWordLength = sjisCurDoubleBytesWordLength; } } else { //sjisLowChars++; sjisCurKatakanaWordLength = 0; sjisCurDoubleBytesWordLength = 0; } } } if canBeUTF8 && utf8BytesLeft > 0 { canBeUTF8 = false; } if canBeShiftJIS && sjisBytesLeft > 0 { canBeShiftJIS = false; } // Easy -- if there is BOM or at least 1 valid not-single byte character (and no evidence it can't be UTF-8), done if canBeUTF8 && (utf8bom || utf2BytesChars + utf3BytesChars + utf4BytesChars > 0) { return encoding::all::UTF_8; } // Easy -- if assuming Shift_JIS or >= 3 valid consecutive not-ascii characters (and no evidence it can't be), done if canBeShiftJIS && (ASSUME_SHIFT_JIS || sjisMaxKatakanaWordLength >= 3 || sjisMaxDoubleBytesWordLength >= 3) { return SHIFT_JIS_CHARSET; } // Distinguishing Shift_JIS and ISO-8859-1 can be a little tough for short words. The crude heuristic is: // - If we saw // - only two consecutive katakana chars in the whole text, or // - at least 10% of bytes that could be "upper" not-alphanumeric Latin1, // - then we conclude Shift_JIS, else ISO-8859-1 if canBeISO88591 && canBeShiftJIS { return if (sjisMaxKatakanaWordLength == 2 && sjisKatakanaChars == 2) || isoHighOther * 10 >= length { SHIFT_JIS_CHARSET } else { encoding::all::ISO_8859_1 }; } // Otherwise, try in order ISO-8859-1, Shift JIS, UTF-8 and fall back to default platform encoding if canBeISO88591 { return encoding::all::ISO_8859_1; } if canBeShiftJIS { return SHIFT_JIS_CHARSET; } if canBeUTF8 { return encoding::all::UTF_8; } // Otherwise, we take a wild guess with platform encoding return PLATFORM_DEFAULT_ENCODING; } } /* * 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; static EMPTY_BITS: [u32; 0] = [0; 0]; static LOAD_FACTOR: f32 = 0.75f32; /** *

A simple, fast array of bits, represented compactly by an array of ints internally.

* * @author Sean Owen */ #[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)] pub struct BitArray { bits: Vec, size: usize, } impl BitArray { pub fn new() -> Self { Self { bits: EMPTY_BITS, size: 0, } } pub fn with_size(size: usize) -> Self { Self { bits: BitArray::makeArray(size), size: size, } } // For testing only pub fn with_initial_values(bits: Vec, size: usize) -> Self { Self { bits: bits, size: size, } } pub fn getSize(&self) -> usize { self.size } pub fn getSizeInBytes(&self) -> usize { return (self.size + 7) / 8; } fn ensureCapacity(&self, newSize: usize) { if newSize > self.bits.len() * 32 { let newBits = BitArray::makeArray((newSize as f32 / LOAD_FACTOR).ceil()); //System.arraycopy(bits, 0, newBits, 0, bits.length); newBits[0..self.bits.len()].clone_from_slice(&self.bits[0..self.bits.len()]); self.bits = newBits; } } /** * @param i bit to get * @return true iff bit i is set */ pub fn get(&self, i: usize) -> bool { return (self.bits[i / 32] & (1 << (i & 0x1F))) != 0; } /** * Sets bit i. * * @param i bit to set */ pub fn set(&self, i: usize) { self.bits[i / 32] |= 1 << (i & 0x1F); } /** * Flips bit i. * * @param i bit to set */ pub fn flip(&self, i: usize) { self.bits[i / 32] ^= 1 << (i & 0x1F); } /** * @param from first bit to check * @return index of first bit that is set, starting from the given index, or size if none are set * at or beyond this given index * @see #getNextUnset(int) */ pub fn getNextSet(&self, from: usize) -> usize { if from >= self.size { return self.size; } let bitsOffset = from / 32; let currentBits = self.bits[bitsOffset]; // mask off lesser bits first currentBits &= -(1 << (from & 0x1F)); while currentBits == 0 { bitsOffset += 1; if bitsOffset == self.bits.len() { return self.size; } currentBits = self.bits[bitsOffset]; } let result = (bitsOffset * 32) + currentBits.trailing_zeros(); cmp::min(result, self.size) } /** * @param from index to start looking for unset bit * @return index of next unset bit, or {@code size} if none are unset until the end * @see #getNextSet(int) */ pub fn getNextUnset(&self, from: usize) -> usize { if from >= self.size { return self.size; } let bitsOffset = from / 32; let currentBits = !self.bits[bitsOffset]; // mask off lesser bits first currentBits &= -(1 << (from & 0x1F)); while currentBits == 0 { bitsOffset += 1; if bitsOffset == self.bits.len() { return self.size; } currentBits = !self.bits[bitsOffset]; } let result = (bitsOffset * 32) + currentBits.trailing_zeros(); return cmp::min(result, self.size); } /** * Sets a block of 32 bits, starting at bit i. * * @param i first bit to set * @param newBits the new value of the next 32 bits. Note again that the least-significant bit * corresponds to bit i, the next-least-significant to i+1, and so on. */ pub fn setBulk(&self, i: usize, newBits: u32) { self.bits[i / 32] = newBits; } /** * Sets a range of bits. * * @param start start of range, inclusive. * @param end end of range, exclusive */ pub fn setRange(&self, start: usize, end: usize) -> Result<(), IllegalArgumentException> { if end < start || start < 0 || end > self.size { return Err(IllegalArgumentException::new( "end < start || start < 0 || end > self.size", )); } if end == start { return; } end -= 1; // will be easier to treat this as the last actually set bit -- inclusive let firstInt = start / 32; let lastInt = end / 32; for i in firstInt..=lastInt { //for (int i = firstInt; i <= lastInt; i++) { let firstBit = if i > firstInt { 0 } else { start & 0x1F }; let lastBit = if i < lastInt { 31 } else { end & 0x1F }; // Ones from firstBit to lastBit, inclusive let mask = (2 << lastBit) - (1 << firstBit); self.bits[i] |= mask; } Ok(()) } /** * Clears all bits (sets to false). */ pub fn clear(&self) { let max = self.bits.length; for i in 0..max { //for (int i = 0; i < max; i++) { self.bits[i] = 0; } } /** * Efficient method to check if a range of bits is set, or not set. * * @param start start of range, inclusive. * @param end end of range, exclusive * @param value if true, checks that bits in range are set, otherwise checks that they are not set * @return true iff all bits are set or not set in range, according to value argument * @throws IllegalArgumentException if end is less than start or the range is not contained in the array */ pub fn isRange( &self, start: usize, end: usize, value: bool, ) -> Result { if end < start || start < 0 || end > self.size { return Err(IllegalArgumentException::new( "end < start || start < 0 || end > self.size", )); } if end == start { return Ok(true); // empty range matches } end -= 1; // will be easier to treat this as the last actually set bit -- inclusive let firstInt = start / 32; let lastInt = end / 32; for i in firstInt..=lastInt { //for (int i = firstInt; i <= lastInt; i++) { let firstBit = if i > firstInt { 0 } else { start & 0x1F }; let lastBit = if i < lastInt { 31 } else { end & 0x1F }; // Ones from firstBit to lastBit, inclusive let mask = (2 << lastBit) - (1 << firstBit); // Return false if we're looking for 1s and the masked bits[i] isn't all 1s (that is, // equals the mask, or we're looking for 0s and the masked portion is not all 0s if (self.bits[i] & mask) != (if value { mask } else { 0 }) { return Ok(false); } } return Ok(true); } pub fn appendBit(&self, bit: bool) { self.ensureCapacity(self.size + 1); if bit { self.bits[self.size / 32] |= 1 << (self.size & 0x1F); } self.size += 1; } /** * Appends the least-significant bits, from value, in order from most-significant to * least-significant. For example, appending 6 bits from 0x000001E will append the bits * 0, 1, 1, 1, 1, 0 in that order. * * @param value {@code int} containing bits to append * @param numBits bits from value to append */ pub fn appendBits(&self, value: u32, numBits: usize) -> Result<(), IllegalArgumentException> { if numBits < 0 || numBits > 32 { return Err(IllegalArgumentException::new( "Num bits must be between 0 and 32", )); } let nextSize = self.size; self.ensureCapacity(nextSize + numBits); for numBitsLeft in (0..(numBits - 1)).rev() { //for (int numBitsLeft = numBits - 1; numBitsLeft >= 0; numBitsLeft--) { if (value & (1 << numBitsLeft)) != 0 { self.bits[nextSize / 32] |= 1 << (nextSize & 0x1F); } nextSize += 1; } self.size = nextSize; Ok(()) } pub fn appendBitArray(&self, other: BitArray) { let otherSize = other.size; self.ensureCapacity(self.size + otherSize); for i in 0..otherSize { //for (int i = 0; i < otherSize; i++) { self.appendBit(other.get(i)); } } pub fn xor(&self, other: &BitArray) -> Result<(), IllegalArgumentException> { if self.size != other.size { return Err(IllegalArgumentException::new("Sizes don't match")); } for i in 0..self.bits.len() { //for (int i = 0; i < bits.length; i++) { // The last int could be incomplete (i.e. not have 32 bits in // it) but there is no problem since 0 XOR 0 == 0. self.bits[i] ^= other.bits[i]; } Ok(()) } /** * * @param bitOffset first bit to start writing * @param array array to write into. Bytes are written most-significant byte first. This is the opposite * of the internal representation, which is exposed by {@link #getBitArray()} * @param offset position in array to start writing * @param numBytes how many bytes to write */ pub fn toBytes(&self, bitOffset: usize, array: &mut [u8], offset: usize, numBytes: usize) { for i in 0..numBytes { //for (int i = 0; i < numBytes; i++) { let theByte = 0; for j in 0..8 { //for (int j = 0; j < 8; j++) { if self.get(bitOffset) { theByte |= 1 << (7 - j); } bitOffset += 1; } array[offset + i] = theByte; } } /** * @return underlying array of ints. The first element holds the first 32 bits, and the least * significant bit is bit 0. */ pub fn getBitArray(&self) -> Vec { return self.bits; } /** * Reverses all bits in the array. */ pub fn reverse(&self) { let newBits = Vec::with_capacity(self.bits.len()); // reverse all int's first let len = (self.size - 1) / 32; let oldBitsLen = len + 1; for i in 0..oldBitsLen { //for (int i = 0; i < oldBitsLen; i++) { newBits[len - i] = self.bits[i].reverse_bits(); } // now correct the int's if the bit size isn't a multiple of 32 if self.size != oldBitsLen * 32 { let leftOffset = oldBitsLen * 32 - self.size; let currentInt = newBits[0] >> leftOffset; for i in 1..oldBitsLen { //for (int i = 1; i < oldBitsLen; i++) { let nextInt = newBits[i]; currentInt |= nextInt << (32 - leftOffset); newBits[i - 1] = currentInt; currentInt = nextInt >> leftOffset; } newBits[oldBitsLen - 1] = currentInt; } self.bits = newBits; } fn makeArray(size: usize) -> Vec { return vec![0; (size + 31) / 32]; } // @Override // public boolean equals(Object o) { // if (!(o instanceof BitArray)) { // return false; // } // BitArray other = (BitArray) o; // return size == other.size && Arrays.equals(bits, other.bits); // } // @Override // public int hashCode() { // return 31 * size + Arrays.hashCode(bits); // } // @Override // public BitArray clone() { // return new BitArray(bits.clone(), size); // } } impl fmt::Display for BitArray { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let _str = String::with_capacity(self.size + (self.size / 8) + 1); for i in 0..self.size { //for (int i = 0; i < size; i++) { if (i & 0x07) == 0 { _str.push_str(" "); } _str.push_str(if self.get(i) { "X" } else { "." }); } write!(f, "{}", _str) } } /* * 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 com.google.zxing.RXingResultPoint; /** *

Encapsulates the result of detecting a barcode in an image. This includes the raw * matrix of black/white pixels corresponding to the barcode, and possibly points of interest * in the image, like the location of finder patterns or corners of the barcode in the image.

* * @author Sean Owen */ pub struct DetectorRXingResult { bits: BitMatrix, points: Vec, } impl DetectorRXingResult { pub fn new(bits: BitMatrix, points: Vec) -> Self { Self { bits: bits, points: points, } } pub fn getBits(&self) -> BitMatrix { return self.bits; } pub fn getPoints(&self) -> Vec { return self.points; } } /* * 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; /** *

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, Copy, PartialEq, Eq, Hash)] pub struct BitMatrix { width: u32, height: u32, rowSize: usize, bits: Vec, } impl BitMatrix { /** * Creates an empty square {@code BitMatrix}. * * @param dimension height and width */ pub fn with_single_dimension(dimension: u32) -> Self { Self::new(dimension, dimension) } /** * Creates an empty {@code BitMatrix}. * * @param width bit matrix width * @param height bit matrix height */ pub fn new(width: u32, height: u32) -> Result { if width < 1 || height < 1 { return Err(IllegalArgumentException::new( "Both dimensions must be greater than 0", )); } Ok(Self { width, height, rowSize: (width + 31) / 32, bits: vec![0; ((width + 31) / 32) * height], }) // this.width = width; // this.height = height; // this.rowSize = (width + 31) / 32; // bits = new int[rowSize * height]; } fn with_all_data(&self, width: u32, height: u32, rowSize: usize, bits: Vec) -> Self { Self { width, height, rowSize, bits, } } /** * Interprets a 2D array of booleans as a {@code BitMatrix}, where "true" means an "on" bit. * * @param image bits of the image, as a row-major 2D array. Elements are arrays representing rows * @return {@code BitMatrix} representation of image */ pub fn parse(image: &[[bool]]) -> Self { let height = image.len(); let width = image[0].len(); let bits = BitMatrix::new(width, height).unwrap(); for i in 0..height { //for (int i = 0; i < height; i++) { let imageI = image[i]; for j in 0..width { //for (int j = 0; j < width; j++) { if imageI[j] { bits.set(j, i); } } } return bits; } pub fn parse( stringRepresentation: &str, setString: &str, unsetString: &str, ) -> Result { // cannot pass nulls in rust // if (stringRepresentation == null) { // throw new IllegalArgumentException(); // } let bits = Vec::with_capacity(stringRepresentation.length()); let bitsPos = 0; let rowStartPos = 0; let rowLength = -1; let nRows = 0; let pos = 0; while pos < stringRepresentation.length() { if stringRepresentation.charAt(pos) == '\n' || stringRepresentation.charAt(pos) == '\r' { if bitsPos > rowStartPos { if rowLength == -1 { rowLength = bitsPos - rowStartPos; } else if bitsPos - rowStartPos != rowLength { return Err(IllegalArgumentException::new("row lengths do not match")); } rowStartPos = bitsPos; nRows += 1; } pos += 1; } else if stringRepresentation.startsWith(setString, pos) { pos += setString.length(); bits[bitsPos] = true; bitsPos += 1; } else if stringRepresentation.startsWith(unsetString, pos) { pos += unsetString.length(); bits[bitsPos] = false; bitsPos += 1; } else { return Err(IllegalArgumentException::new(&format!( "illegal character encountered: {}", stringRepresentation.substring(pos) ))); } } // no EOL at end? if bitsPos > rowStartPos { if rowLength == -1 { rowLength = bitsPos - rowStartPos; } else if bitsPos - rowStartPos != rowLength { return Err(IllegalArgumentException::new("row lengths do not match")); } nRows += 1; } let matrix = BitMatrix::new(rowLength, nRows); for i in 0..bitsPos { //for (int i = 0; i < bitsPos; i++) { if bits[i] { matrix.set(i % rowLength, i / rowLength); } } return matrix; } /** *

Gets 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 = y * self.rowSize + (x / 32); return ((self.bits[offset] >> (x & 0x1f)) & 1) != 0; } /** *

Sets 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(&self, x: u32, y: u32) { let offset = y * self.rowSize + (x / 32); self.bits[offset] |= 1 << (x & 0x1f); } pub fn unset(&self, x: u32, y: u32) { let offset = y * self.rowSize + (x / 32); 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(&self, x: u32, y: u32) { let offset = y * self.rowSize + (x / 32); self.bits[offset] ^= 1 << (x & 0x1f); } /** *

Flips every bit in the matrix.

*/ pub fn flip(&self) { let max = self.bits.len(); for i in 0..max { //for (int i = 0; i < max; i++) { self.bits[i] = !self.bits[i]; } } /** * Exclusive-or (XOR): Flip the bit in this {@code BitMatrix} if the corresponding * mask bit is set. * * @param mask XOR mask */ pub fn xor(&self, mask: &BitMatrix) -> Result<(), IllegalArgumentException> { if self.width != mask.width || self.height != mask.height || self.rowSize != mask.rowSize { return Err(IllegalArgumentException::new( "input matrix dimensions do not match", )); } let rowArray = BitArray::with_size(self.width); for y in 0..self.height { //for (int y = 0; y < height; y++) { let offset = y * self.rowSize; let row = mask.getRow(y, self.rowArray).getBitArray(); for x in 0..self.rowSize { //for (int x = 0; x < rowSize; x++) { self.bits[offset + x] ^= row[x]; } } Ok(()) } /** * Clears all bits (sets to false). */ pub fn clear(&self) { let max = self.bits.len(); for i in 0..max { //for (int i = 0; i < max; i++) { self.bits[i] = 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( &self, left: u32, top: u32, width: u32, height: u32, ) -> Result<(), IllegalArgumentException> { if top < 0 || left < 0 { return Err(IllegalArgumentException::new( "Left and top must be nonnegative", )); } if height < 1 || width < 1 { return Err(IllegalArgumentException::new( "Height and width must be at least 1", )); } let right = left + width; let bottom = top + height; if bottom > self.height || right > self.width { return Err(IllegalArgumentException::new( "The region must fit inside the matrix", )); } for y in top..bottom { //for (int y = top; y < bottom; y++) { let offset = y * self.rowSize; for x in left..right { //for (int x = left; x < right; x++) { self.bits[offset + (x / 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, row: &BitArray) -> BitArray { let rw: BitArray = if row.getSize() < self.width { row = &BitArray::with_size(self.width) } else { row.clear(); row }; let offset = y * self.rowSize; for x in 0..self.rowSize { //for (int x = 0; x < rowSize; x++) { rw.setBulk(x * 32, self.bits[offset + x]); } return rw; } /** * @param y row to set * @param row {@link BitArray} to copy from */ pub fn setRow(&self, y: u32, row: &BitArray) { return self.bits[y * self.rowSize..self.rowSize] .clone_from_slice(&row.getBitArray()[0..self.rowSize]); //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(&self, degrees: u32) -> Result<(), IllegalArgumentException> { match degrees % 360 { 0 => Ok(()), 90 => { self.rotate90(); Ok(()) } 180 => { self.rotate180(); Ok(()) } 270 => { self.rotate90(); self.rotate180(); Ok(()) } _ => Err(IllegalArgumentException::new( "degrees must be a multiple of 0, 90, 180, or 270", )), } } /** * Modifies this {@code BitMatrix} to represent the same but rotated 180 degrees */ pub fn rotate180(&self) { let mut topRow = BitArray::with_size(self.width); let mut bottomRow = BitArray::with_size(self.width); let mut maxHeight = (self.height + 1) / 2; for i in 0..maxHeight { //for (int i = 0; i < maxHeight; i++) { topRow = self.getRow(i, &topRow); let bottomRowIndex = self.height - 1 - i; bottomRow = self.getRow(bottomRowIndex, &bottomRow); 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(&self) { let mut newWidth = self.height; let mut newHeight = self.width; let mut newRowSize = (newWidth + 31) / 32; let mut newBits = Vec::with_capacity(newRowSize * newHeight); 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 = y * self.rowSize + (x / 32); if ((self.bits[offset] >> (x & 0x1f)) & 1) != 0 { let newOffset = (newHeight - 1 - x) * newRowSize + (y / 32); newBits[newOffset] |= 1 << (y & 0x1f); } } } self.width = newWidth; self.height = newHeight; self.rowSize = newRowSize; 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> { let left = self.width; let top = self.height; let right = -1; let bottom = -1; for y in 0..self.height { //for (int y = 0; y < height; y++) { for x32 in 0..self.rowSize { //for (int x32 = 0; x32 < rowSize; x32++) { let theBits = self.bits[y * self.rowSize + x32]; if theBits != 0 { if y < top { top = y; } if y > bottom { bottom = y; } if x32 * 32 < left { let bit = 0; while (theBits << (31 - bit)) == 0 { bit += 1; } if (x32 * 32 + bit) < left { left = x32 * 32 + bit; } } if x32 * 32 + 31 > right { let bit = 31; while (theBits >> bit) == 0 { bit -= 1; } if (x32 * 32 + bit) > right { right = x32 * 32 + bit; } } } } } if right < left || bottom < top { return None; } return Some(vec![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> { let bitsOffset = 0; while bitsOffset < self.bits.length && self.bits[bitsOffset] == 0 { bitsOffset += 1; } if bitsOffset == self.bits.length { return None; } let y = bitsOffset / self.rowSize; let x = (bitsOffset % self.rowSize) * 32; let theBits = self.bits[bitsOffset]; let bit = 0; while (theBits << (31 - bit)) == 0 { bit += 1; } x += bit; return Some(vec![x, y]); } pub fn getBottomRightOnBit(&self) -> Option> { let bitsOffset = self.bits.length - 1; while bitsOffset >= 0 && self.bits[bitsOffset] == 0 { bitsOffset -= 1; } if bitsOffset < 0 { return None; } let y = bitsOffset / self.rowSize; let x = (bitsOffset % self.rowSize) * 32; let theBits = self.bits[bitsOffset]; let bit = 31; while (theBits >> bit) == 0 { bit -= 1; } x += bit; return Some(vec![x, y]); } /** * @return The width of the matrix */ pub fn getWidth(&self) -> u32 { return self.width; } /** * @return The height of the matrix */ pub fn getHeight(&self) -> u32 { return self.height; } /** * @return The row size of the matrix */ pub fn getRowSize(&self) -> usize { return self.rowSize; } // @Override // public boolean equals(Object o) { // if (!(o instanceof BitMatrix)) { // return false; // } // BitMatrix other = (BitMatrix) o; // return width == other.width && height == other.height && rowSize == other.rowSize && // Arrays.equals(bits, other.bits); // } // @Override // public int hashCode() { // int hash = width; // hash = 31 * hash + width; // hash = 31 * hash + height; // hash = 31 * hash + rowSize; // hash = 31 * hash + Arrays.hashCode(bits); // return hash; // } /** * @param setString representation of a set bit * @param unsetString representation of an unset bit * @return string representation of entire matrix utilizing given strings */ pub fn toString(&self, setString: &str, unsetString: &str) -> String { return self.buildToString(setString, unsetString, "\n"); } /** * @param setString representation of a set bit * @param unsetString representation of an unset bit * @param lineSeparator newline character in string representation * @return string representation of entire matrix utilizing given strings and line separator * @deprecated call {@link #toString(String,String)} only, which uses \n line separator always */ // @Deprecated // public String toString(String setString, String unsetString, String lineSeparator) { // return buildToString(setString, unsetString, lineSeparator); // } fn buildToString(&self, setString: &str, unsetString: &str, lineSeparator: &str) -> String { let result = String::with_capacity(self.height * (self.width + 1)); 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++) { result.push_str(if self.get(x, y) { setString } else { unsetString }); } result.push_str(lineSeparator); } return result; } // @Override // public BitMatrix clone() { // return new BitMatrix(width, height, rowSize, bits.clone()); // } } impl fmt::Display for BitMatrix { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}", self.toString("X ", " ")) } } /* * Copyright 2021 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; /** * Interface to navigate a sequence of ECIs and bytes. * * @author Alex Geller */ pub trait ECIInput { /** * Returns the length of this input. The length is the number * of {@code byte}s in or ECIs in the sequence. * * @return the number of {@code char}s in this sequence */ fn length() -> usize; /** * Returns the {@code byte} value at the specified index. An index ranges from zero * to {@code length() - 1}. The first {@code byte} value of the sequence is at * index zero, the next at index one, and so on, as for array * indexing. * * @param index the index of the {@code byte} value to be returned * * @return the specified {@code byte} value as character or the FNC1 character * * @throws IndexOutOfBoundsException * if the {@code index} argument is negative or not less than * {@code length()} * @throws IllegalArgumentException * if the value at the {@code index} argument is an ECI (@see #isECI) */ fn charAt(index: usize) -> char; /** * Returns a {@code CharSequence} that is a subsequence of this sequence. * The subsequence starts with the {@code char} value at the specified index and * ends with the {@code char} value at index {@code end - 1}. The length * (in {@code char}s) of the * returned sequence is {@code end - start}, so if {@code start == end} * then an empty sequence is returned. * * @param start the start index, inclusive * @param end the end index, exclusive * * @return the specified subsequence * * @throws IndexOutOfBoundsException * if {@code start} or {@code end} are negative, * if {@code end} is greater than {@code length()}, * or if {@code start} is greater than {@code end} * @throws IllegalArgumentException * if a value in the range {@code start}-{@code end} is an ECI (@see #isECI) */ fn subSequence(start: usize, end: usize) -> Vec; /** * Determines if a value is an ECI * * @param index the index of the value * * @return true if the value at position {@code index} is an ECI * * @throws IndexOutOfBoundsException * if the {@code index} argument is negative or not less than * {@code length()} */ fn isECI(index: u32) -> bool; /** * Returns the {@code int} ECI value at the specified index. An index ranges from zero * to {@code length() - 1}. The first {@code byte} value of the sequence is at * index zero, the next at index one, and so on, as for array * indexing. * * @param index the index of the {@code int} value to be returned * * @return the specified {@code int} ECI value. * The ECI specified the encoding of all bytes with a higher index until the * next ECI or until the end of the input if no other ECI follows. * * @throws IndexOutOfBoundsException * if the {@code index} argument is negative or not less than * {@code length()} * @throws IllegalArgumentException * if the value at the {@code index} argument is not an ECI (@see #isECI) */ fn getECIValue(index: usize) -> u32; fn haveNCharacters(index: usize, n: usize) -> bool; } /* * 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; /** *

This provides an easy abstraction to read bits at a time from a sequence of bytes, where the * number of bits read is not often a multiple of 8.

* *

This class is thread-safe but not reentrant -- unless the caller modifies the bytes array * it passed in, in which case all bets are off.

* * @author Sean Owen */ pub struct BitSource { bytes: Vec, byteOffset: usize, bitOffset: usize, } impl BitSource { /** * @param bytes bytes from which this will read bits. Bits will be read from the first byte first. * Bits are read within a byte from most-significant to least-significant bit. */ pub fn new(bytes: Vec) -> Self { Self { bytes, byteOffset: 0, bitOffset: 0, } } /** * @return index of next bit in current byte which would be read by the next call to {@link #readBits(int)}. */ pub fn getBitOffset(&self) -> usize { return self.bitOffset; } /** * @return index of next byte in input byte array which would be read by the next call to {@link #readBits(int)}. */ pub fn getByteOffset(&self) -> usize { return self.byteOffset; } /** * @param numBits number of bits to read * @return int representing the bits read. The bits will appear as the least-significant * bits of the int * @throws IllegalArgumentException if numBits isn't in [1,32] or more than is available */ pub fn readBits(&self, numBits: usize) -> Result { if numBits < 1 || numBits > 32 || numBits > self.available() { return Err(IllegalArgumentException::new(numBits)); } let result = 0; // First, read remainder from current byte if self.bitOffset > 0 { let bitsLeft = 8 - self.bitOffset; let toRead = cmp::min(numBits, bitsLeft); let bitsToNotRead = bitsLeft - toRead; let mask = (0xFF >> (8 - toRead)) << bitsToNotRead; result = (self.bytes[self.byteOffset] & mask) >> bitsToNotRead; numBits -= toRead; self.bitOffset += toRead; if self.bitOffset == 8 { self.bitOffset = 0; self.byteOffset += 1; } } // Next read whole bytes if numBits > 0 { while numBits >= 8 { result = (result << 8) | (self.bytes[self.byteOffset] & 0xFF); self.byteOffset += 1; numBits -= 8; } // Finally read a partial byte if numBits > 0 { let bitsToNotRead = 8 - numBits; let mask = (0xFF >> bitsToNotRead) << bitsToNotRead; result = (result << numBits) | ((self.bytes[self.byteOffset] & mask) >> bitsToNotRead); self.bitOffset += numBits; } } return Ok(result); } /** * @return number of bits that can be read successfully */ pub fn available(&self) -> u32 { return 8 * (self.bytes.len() - self.byteOffset) - self.bitOffset; } }