mirror of
https://github.com/starovoid/rxing.git
synced 2026-07-26 04:12:34 +00:00
2070 lines
67 KiB
Rust
2070 lines
67 KiB
Rust
pub mod detector;
|
|
pub mod reedsolomon;
|
|
|
|
use core::num;
|
|
use std::any::Any;
|
|
use std::cmp;
|
|
use std::collections::HashMap;
|
|
use std::fmt;
|
|
|
|
use crate::DecodeHintType;
|
|
use crate::Exceptions;
|
|
use crate::RXingResultPoint;
|
|
use encoding::Encoding;
|
|
|
|
#[cfg(test)]
|
|
mod StringUtilsTestCase;
|
|
|
|
#[cfg(test)]
|
|
mod BitArrayTestCase;
|
|
|
|
#[cfg(test)]
|
|
mod BitMatrixTestCase;
|
|
|
|
#[cfg(test)]
|
|
mod BitSourceTestCase;
|
|
|
|
#[cfg(test)]
|
|
mod PerspectiveTransformTestCase;
|
|
/*
|
|
* 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").unwrap();
|
|
// const GB2312_CHARSET: &dyn Encoding =
|
|
// encoding::label::encoding_from_whatwg_label("GB2312").unwrap();
|
|
// const EUC_JP: &dyn Encoding = encoding::label::encoding_from_whatwg_label("EUC_JP").unwrap();
|
|
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<DecodeHintType, String>) -> String {
|
|
let c = StringUtils::guessCharset(bytes, hints);
|
|
if c.name()
|
|
== encoding::label::encoding_from_whatwg_label("SJIS")
|
|
.unwrap()
|
|
.name()
|
|
{
|
|
return "SJIS".to_owned();
|
|
} else if c.name() == encoding::all::UTF_8.name() {
|
|
return "UTF8".to_owned();
|
|
} else if c.name() == encoding::all::ISO_8859_1.name() {
|
|
return "ISO8859_1".to_owned();
|
|
}
|
|
return c.name().to_owned();
|
|
}
|
|
|
|
/**
|
|
* @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<DecodeHintType, String>,
|
|
) -> &'static dyn Encoding {
|
|
match hints.get(&DecodeHintType::CHARACTER_SET) {
|
|
Some(hint) => {
|
|
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))
|
|
{
|
|
if bytes[0] == 0xFE && bytes[1] == 0xFF {
|
|
return encoding::all::UTF_16BE;
|
|
} else {
|
|
return encoding::all::UTF_16LE;
|
|
}
|
|
}
|
|
|
|
// 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 mut canBeISO88591 = true;
|
|
let mut canBeShiftJIS = true;
|
|
let mut canBeUTF8 = true;
|
|
let mut utf8BytesLeft = 0;
|
|
let mut utf2BytesChars = 0;
|
|
let mut utf3BytesChars = 0;
|
|
let mut utf4BytesChars = 0;
|
|
let mut sjisBytesLeft = 0;
|
|
let mut sjisKatakanaChars = 0;
|
|
let mut sjisCurKatakanaWordLength = 0;
|
|
let mut sjisCurDoubleBytesWordLength = 0;
|
|
let mut sjisMaxKatakanaWordLength = 0;
|
|
let mut sjisMaxDoubleBytesWordLength = 0;
|
|
let mut 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 encoding::label::encoding_from_whatwg_label("SJIS").unwrap();
|
|
}
|
|
// 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
|
|
{
|
|
encoding::label::encoding_from_whatwg_label("SJIS").unwrap()
|
|
} 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 encoding::label::encoding_from_whatwg_label("SJIS").unwrap();
|
|
}
|
|
if canBeUTF8 {
|
|
return encoding::all::UTF_8;
|
|
}
|
|
// Otherwise, we take a wild guess with platform encoding
|
|
return encoding::all::UTF_8;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* 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;
|
|
|
|
/**
|
|
* <p>A simple, fast array of bits, represented compactly by an array of ints internally.</p>
|
|
*
|
|
* @author Sean Owen
|
|
*/
|
|
#[derive(Debug, PartialEq, Eq, Clone, Hash)]
|
|
pub struct BitArray {
|
|
bits: Vec<u32>,
|
|
size: usize,
|
|
}
|
|
|
|
impl BitArray {
|
|
pub fn new() -> Self {
|
|
Self {
|
|
bits: EMPTY_BITS.to_vec(),
|
|
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<u32>, 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(&mut self, newSize: usize) {
|
|
if newSize > self.bits.len() * 32 {
|
|
let mut newBits = BitArray::makeArray((newSize as f32 / LOAD_FACTOR).ceil() as usize);
|
|
//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(&mut self, i: usize) {
|
|
self.bits[i / 32] |= 1 << (i & 0x1F);
|
|
}
|
|
|
|
/**
|
|
* Flips bit i.
|
|
*
|
|
* @param i bit to set
|
|
*/
|
|
pub fn flip(&mut 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 mut bitsOffset = from / 32;
|
|
let mut currentBits = self.bits[bitsOffset] as i64;
|
|
// 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] as i64;
|
|
}
|
|
let result = (bitsOffset * 32) + currentBits.trailing_zeros() as usize;
|
|
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 mut bitsOffset = from / 32;
|
|
let mut currentBits = !self.bits[bitsOffset] as i32;
|
|
// 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] as i32;
|
|
}
|
|
let result = (bitsOffset * 32) + currentBits.trailing_zeros() as usize;
|
|
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(&mut 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(&mut self, start: usize, end: usize) -> Result<(), Exceptions> {
|
|
let mut end = end;
|
|
if end < start || start < 0 || end > self.size {
|
|
return Err(Exceptions::IllegalArgumentException(
|
|
"end < start || start < 0 || end > self.size".to_owned(),
|
|
));
|
|
}
|
|
if end == start {
|
|
return Ok(());
|
|
}
|
|
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: u64 = (2 << lastBit) - (1 << firstBit);
|
|
self.bits[i] |= mask as u32;
|
|
}
|
|
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;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 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<bool, Exceptions> {
|
|
let mut end = end;
|
|
if end < start || start < 0 || end > self.size {
|
|
return Err(Exceptions::IllegalArgumentException(
|
|
"end < start || start < 0 || end > self.size".to_owned(),
|
|
));
|
|
}
|
|
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: u64 = (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 as u32) != (if value { mask as u32 } else { 0 }) {
|
|
return Ok(false);
|
|
}
|
|
}
|
|
return Ok(true);
|
|
}
|
|
|
|
pub fn appendBit(&mut 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(&mut self, value: u32, numBits: usize) -> Result<(), Exceptions> {
|
|
if numBits < 0 || numBits > 32 {
|
|
return Err(Exceptions::IllegalArgumentException(
|
|
"Num bits must be between 0 and 32".to_owned(),
|
|
));
|
|
}
|
|
let mut 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(&mut 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(&mut self, other: &BitArray) -> Result<(), Exceptions> {
|
|
if self.size != other.size {
|
|
return Err(Exceptions::IllegalArgumentException(
|
|
"Sizes don't match".to_owned(),
|
|
));
|
|
}
|
|
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) {
|
|
let mut bitOffset = bitOffset;
|
|
for i in 0..numBytes {
|
|
//for (int i = 0; i < numBytes; i++) {
|
|
let mut 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<u32> {
|
|
return &self.bits;
|
|
}
|
|
|
|
/**
|
|
* Reverses all bits in the array.
|
|
*/
|
|
pub fn reverse(&mut self) {
|
|
let mut newBits = vec![0; 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 mut 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<u32> {
|
|
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 mut _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;
|
|
|
|
/**
|
|
* <p>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.</p>
|
|
*
|
|
* @author Sean Owen
|
|
*/
|
|
pub struct DetectorRXingResult {
|
|
bits: BitMatrix,
|
|
points: Vec<RXingResultPoint>,
|
|
}
|
|
|
|
impl DetectorRXingResult {
|
|
pub fn new(bits: BitMatrix, points: Vec<RXingResultPoint>) -> Self {
|
|
Self {
|
|
bits: bits,
|
|
points: points,
|
|
}
|
|
}
|
|
|
|
pub fn getBits(&self) -> &BitMatrix {
|
|
return &self.bits;
|
|
}
|
|
|
|
pub fn getPoints(&self) -> &Vec<RXingResultPoint> {
|
|
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;
|
|
|
|
/**
|
|
* <p>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.</p>
|
|
*
|
|
* <p>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.</p>
|
|
*
|
|
* <p>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.</p>
|
|
*
|
|
* @author Sean Owen
|
|
* @author dswitkin@google.com (Daniel Switkin)
|
|
*/
|
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
|
pub struct BitMatrix {
|
|
width: u32,
|
|
height: u32,
|
|
rowSize: usize,
|
|
bits: Vec<u32>,
|
|
}
|
|
|
|
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).unwrap()
|
|
}
|
|
|
|
/**
|
|
* Creates an empty {@code BitMatrix}.
|
|
*
|
|
* @param width bit matrix width
|
|
* @param height bit matrix height
|
|
*/
|
|
pub fn new(width: u32, height: u32) -> Result<Self, Exceptions> {
|
|
if width < 1 || height < 1 {
|
|
return Err(Exceptions::IllegalArgumentException(
|
|
"Both dimensions must be greater than 0".to_owned(),
|
|
));
|
|
}
|
|
Ok(Self {
|
|
width,
|
|
height,
|
|
rowSize: ((width + 31) / 32) as usize,
|
|
bits: vec![0; (((width + 31) / 32) * height) as usize],
|
|
})
|
|
// 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<u32>) -> 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_bools(image: &Vec<Vec<bool>>) -> Self {
|
|
let height: u32 = image.len().try_into().unwrap();
|
|
let width: u32 = image[0].len().try_into().unwrap();
|
|
let mut bits = BitMatrix::new(width, height).unwrap();
|
|
for i in 0..height as usize {
|
|
//for (int i = 0; i < height; i++) {
|
|
let imageI = &image[i];
|
|
for j in 0..width as usize {
|
|
//for (int j = 0; j < width; j++) {
|
|
if imageI[j] {
|
|
bits.set(j as u32, i as u32);
|
|
}
|
|
}
|
|
}
|
|
return bits;
|
|
}
|
|
|
|
pub fn parse_strings(
|
|
stringRepresentation: &str,
|
|
setString: &str,
|
|
unsetString: &str,
|
|
) -> Result<Self, Exceptions> {
|
|
// cannot pass nulls in rust
|
|
// if (stringRepresentation == null) {
|
|
// throw new IllegalArgumentException();
|
|
// }
|
|
|
|
let mut bits = vec![false; stringRepresentation.len()];
|
|
let mut bitsPos = 0;
|
|
let mut rowStartPos = 0;
|
|
let mut rowLength = 0; //-1;
|
|
let mut first_run = true;
|
|
let mut nRows = 0;
|
|
let mut pos = 0;
|
|
while pos < stringRepresentation.len() {
|
|
if stringRepresentation.chars().nth(pos).unwrap() == '\n'
|
|
|| stringRepresentation.chars().nth(pos).unwrap() == '\r'
|
|
{
|
|
if bitsPos > rowStartPos {
|
|
//if rowLength == -1 {
|
|
if first_run {
|
|
first_run = false;
|
|
rowLength = bitsPos - rowStartPos;
|
|
} else if bitsPos - rowStartPos != rowLength {
|
|
return Err(Exceptions::IllegalArgumentException(
|
|
"row lengths do not match".to_owned(),
|
|
));
|
|
}
|
|
rowStartPos = bitsPos;
|
|
nRows += 1;
|
|
}
|
|
pos += 1;
|
|
} else if stringRepresentation[pos..].starts_with(setString) {
|
|
pos += setString.len();
|
|
bits[bitsPos] = true;
|
|
bitsPos += 1;
|
|
} else if stringRepresentation[pos..].starts_with(unsetString) {
|
|
pos += unsetString.len();
|
|
bits[bitsPos] = false;
|
|
bitsPos += 1;
|
|
} else {
|
|
return Err(Exceptions::IllegalArgumentException(format!(
|
|
"illegal character encountered: {}",
|
|
stringRepresentation[pos..].to_owned()
|
|
)));
|
|
}
|
|
}
|
|
|
|
// no EOL at end?
|
|
if bitsPos > rowStartPos {
|
|
//if rowLength == -1 {
|
|
if first_run {
|
|
first_run = false;
|
|
rowLength = bitsPos - rowStartPos;
|
|
} else if bitsPos - rowStartPos != rowLength {
|
|
return Err(Exceptions::IllegalArgumentException(
|
|
"row lengths do not match".to_owned(),
|
|
));
|
|
}
|
|
nRows += 1;
|
|
}
|
|
|
|
let mut matrix = BitMatrix::new(rowLength.try_into().unwrap(), nRows)?;
|
|
for i in 0..bitsPos {
|
|
//for (int i = 0; i < bitsPos; i++) {
|
|
if bits[i] {
|
|
matrix.set(
|
|
(i % rowLength).try_into().unwrap(),
|
|
(i / rowLength).try_into().unwrap(),
|
|
);
|
|
}
|
|
}
|
|
return Ok(matrix);
|
|
}
|
|
|
|
/**
|
|
* <p>Gets the requested bit, where true means black.</p>
|
|
*
|
|
* @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 as usize * self.rowSize + (x as usize / 32);
|
|
return ((self.bits[offset] >> (x & 0x1f)) & 1) != 0;
|
|
}
|
|
|
|
/**
|
|
* <p>Sets the given bit to true.</p>
|
|
*
|
|
* @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 = y as usize * self.rowSize + (x as usize / 32);
|
|
self.bits[offset] |= 1 << (x & 0x1f);
|
|
}
|
|
|
|
pub fn unset(&mut self, x: u32, y: u32) {
|
|
let offset = y as usize * self.rowSize + (x as usize / 32);
|
|
self.bits[offset] &= !(1 << (x & 0x1f));
|
|
}
|
|
|
|
/**
|
|
* <p>Flips the given bit.</p>
|
|
*
|
|
* @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 = y as usize * self.rowSize + (x as usize / 32);
|
|
self.bits[offset] ^= 1 << (x & 0x1f);
|
|
}
|
|
|
|
/**
|
|
* <p>Flips every bit in the matrix.</p>
|
|
*/
|
|
pub fn flip_self(&mut 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(&mut self, mask: &BitMatrix) -> Result<(), Exceptions> {
|
|
if self.width != mask.width || self.height != mask.height || self.rowSize != mask.rowSize {
|
|
return Err(Exceptions::IllegalArgumentException(
|
|
"input matrix dimensions do not match".to_owned(),
|
|
));
|
|
}
|
|
let 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.rowSize;
|
|
let tmp = mask.getRow(y, &rowArray);
|
|
let row = tmp.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(&mut self) {
|
|
let max = self.bits.len();
|
|
for i in 0..max {
|
|
//for (int i = 0; i < max; i++) {
|
|
self.bits[i] = 0;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* <p>Sets a square region of the bit matrix to true.</p>
|
|
*
|
|
* @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(
|
|
"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(
|
|
"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.rowSize;
|
|
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, row: &BitArray) -> BitArray {
|
|
let mut rw: BitArray = if row.getSize() < self.width as usize {
|
|
BitArray::with_size(self.width as usize)
|
|
} else {
|
|
let mut z = row.clone();
|
|
z.clear();
|
|
z
|
|
// row.clear();
|
|
// row.clone()
|
|
};
|
|
|
|
let offset = y as usize * 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(&mut self, y: u32, row: &BitArray) {
|
|
return self.bits[y as usize * self.rowSize..y as usize * 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(&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(
|
|
"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 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(&mut self) {
|
|
let mut newWidth = self.height;
|
|
let mut newHeight = self.width;
|
|
let mut newRowSize = (newWidth + 31) / 32;
|
|
let mut newBits = vec![0; (newRowSize * newHeight).try_into().unwrap()];
|
|
|
|
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 as usize * self.rowSize + (x as usize / 32);
|
|
if ((self.bits[offset] >> (x & 0x1f)) & 1) != 0 {
|
|
let newOffset: usize = ((newHeight - 1 - x) * newRowSize + (y / 32))
|
|
.try_into()
|
|
.unwrap();
|
|
newBits[newOffset] |= 1 << (y & 0x1f);
|
|
}
|
|
}
|
|
}
|
|
self.width = newWidth;
|
|
self.height = newHeight;
|
|
self.rowSize = newRowSize.try_into().unwrap();
|
|
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<Vec<u32>> {
|
|
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.rowSize {
|
|
//for (int x32 = 0; x32 < rowSize; x32++) {
|
|
let theBits = self.bits[y as usize * self.rowSize + x32];
|
|
if theBits != 0 {
|
|
if y < top {
|
|
top = y;
|
|
}
|
|
if y > bottom {
|
|
bottom = y;
|
|
}
|
|
if x32 * 32 < left.try_into().unwrap() {
|
|
let mut bit = 0;
|
|
while (theBits << (31 - bit)) == 0 {
|
|
bit += 1;
|
|
}
|
|
if (x32 * 32 + bit) < left.try_into().unwrap() {
|
|
left = (x32 * 32 + bit).try_into().unwrap();
|
|
}
|
|
}
|
|
if x32 * 32 + 31 > right.try_into().unwrap() {
|
|
let mut bit = 31;
|
|
while (theBits >> bit) == 0 {
|
|
bit -= 1;
|
|
}
|
|
if (x32 * 32 + bit) > right.try_into().unwrap() {
|
|
right = (x32 * 32 + bit).try_into().unwrap();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
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<Vec<u32>> {
|
|
let mut bitsOffset = 0;
|
|
while bitsOffset < self.bits.len() && self.bits[bitsOffset] == 0 {
|
|
bitsOffset += 1;
|
|
}
|
|
if bitsOffset == self.bits.len() {
|
|
return None;
|
|
}
|
|
let y = bitsOffset / self.rowSize;
|
|
let mut x = (bitsOffset % self.rowSize) * 32;
|
|
|
|
let theBits = self.bits[bitsOffset];
|
|
let mut bit = 0;
|
|
while (theBits << (31 - bit)) == 0 {
|
|
bit += 1;
|
|
}
|
|
x += bit;
|
|
return Some(vec![x as u32, y as u32]);
|
|
}
|
|
|
|
pub fn getBottomRightOnBit(&self) -> Option<Vec<u32>> {
|
|
let mut bitsOffset = self.bits.len() as i64 - 1;
|
|
while bitsOffset >= 0 && self.bits[bitsOffset as usize] == 0 {
|
|
bitsOffset -= 1;
|
|
}
|
|
if bitsOffset < 0 {
|
|
return None;
|
|
}
|
|
|
|
let y = bitsOffset as usize / self.rowSize;
|
|
let mut x = (bitsOffset as usize % self.rowSize) * 32;
|
|
|
|
let theBits = self.bits[bitsOffset as usize];
|
|
let mut bit = 31;
|
|
while (theBits >> bit) == 0 {
|
|
bit -= 1;
|
|
}
|
|
x += bit;
|
|
|
|
return Some(vec![x as u32, y as u32]);
|
|
}
|
|
|
|
/**
|
|
* @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 mut result =
|
|
String::with_capacity((self.height * (self.width + 1)).try_into().unwrap());
|
|
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<char>;
|
|
|
|
/**
|
|
* 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;
|
|
|
|
/**
|
|
* <p>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.</p>
|
|
*
|
|
* <p>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.</p>
|
|
*
|
|
* @author Sean Owen
|
|
*/
|
|
pub struct BitSource {
|
|
bytes: Vec<u8>,
|
|
byte_offset: usize,
|
|
bit_offset: 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<u8>) -> Self {
|
|
Self {
|
|
bytes,
|
|
byte_offset: 0,
|
|
bit_offset: 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.bit_offset;
|
|
}
|
|
|
|
/**
|
|
* @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.byte_offset;
|
|
}
|
|
|
|
/**
|
|
* @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(&mut self, numBits: usize) -> Result<u32, Exceptions> {
|
|
if numBits < 1 || numBits > 32 || numBits > self.available() {
|
|
return Err(Exceptions::IllegalArgumentException(numBits.to_string()));
|
|
}
|
|
|
|
let mut result = 0;
|
|
|
|
let mut num_bits = numBits;
|
|
|
|
// First, read remainder from current byte
|
|
if self.bit_offset > 0 {
|
|
let bitsLeft = 8 - self.bit_offset;
|
|
let toRead = cmp::min(num_bits, bitsLeft);
|
|
let bitsToNotRead = bitsLeft - toRead;
|
|
let mask = (0xFF >> (8 - toRead)) << bitsToNotRead;
|
|
result = (self.bytes[self.byte_offset] & mask) >> bitsToNotRead;
|
|
num_bits -= toRead;
|
|
self.bit_offset += toRead;
|
|
if self.bit_offset == 8 {
|
|
self.bit_offset = 0;
|
|
self.byte_offset += 1;
|
|
}
|
|
}
|
|
|
|
// Next read whole bytes
|
|
if num_bits > 0 {
|
|
while num_bits >= 8 {
|
|
result = ((result as u16) << 8) as u8 | (self.bytes[self.byte_offset] & 0xFF);
|
|
self.byte_offset += 1;
|
|
num_bits -= 8;
|
|
}
|
|
|
|
// Finally read a partial byte
|
|
if num_bits > 0 {
|
|
let bits_to_not_read = 8 - num_bits;
|
|
let mask = (0xFF >> bits_to_not_read) << bits_to_not_read;
|
|
result = (result << num_bits)
|
|
| ((self.bytes[self.byte_offset] & mask) >> bits_to_not_read);
|
|
self.bit_offset += num_bits;
|
|
}
|
|
}
|
|
|
|
return Ok(result.into());
|
|
}
|
|
|
|
/**
|
|
* @return number of bits that can be read successfully
|
|
*/
|
|
pub fn available(&self) -> usize {
|
|
return 8 * (self.bytes.len() - self.byte_offset) - self.bit_offset;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* 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;
|
|
|
|
/**
|
|
* <p>This class implements a perspective transform in two dimensions. Given four source and four
|
|
* destination points, it will compute the transformation implied between them. The code is based
|
|
* directly upon section 3.4.2 of George Wolberg's "Digital Image Warping"; see pages 54-56.</p>
|
|
*
|
|
* @author Sean Owen
|
|
*/
|
|
pub struct PerspectiveTransform {
|
|
a11: f32,
|
|
a12: f32,
|
|
a13: f32,
|
|
a21: f32,
|
|
a22: f32,
|
|
a23: f32,
|
|
a31: f32,
|
|
a32: f32,
|
|
a33: f32,
|
|
}
|
|
|
|
impl PerspectiveTransform {
|
|
fn new(
|
|
a11: f32,
|
|
a21: f32,
|
|
a31: f32,
|
|
a12: f32,
|
|
a22: f32,
|
|
a32: f32,
|
|
a13: f32,
|
|
a23: f32,
|
|
a33: f32,
|
|
) -> Self {
|
|
Self {
|
|
a11,
|
|
a12,
|
|
a13,
|
|
a21,
|
|
a22,
|
|
a23,
|
|
a31,
|
|
a32,
|
|
a33,
|
|
}
|
|
}
|
|
|
|
pub fn quadrilateralToQuadrilateral(
|
|
x0: f32,
|
|
y0: f32,
|
|
x1: f32,
|
|
y1: f32,
|
|
x2: f32,
|
|
y2: f32,
|
|
x3: f32,
|
|
y3: f32,
|
|
x0p: f32,
|
|
y0p: f32,
|
|
x1p: f32,
|
|
y1p: f32,
|
|
x2p: f32,
|
|
y2p: f32,
|
|
x3p: f32,
|
|
y3p: f32,
|
|
) -> Self {
|
|
let qToS = PerspectiveTransform::quadrilateralToSquare(x0, y0, x1, y1, x2, y2, x3, y3);
|
|
let sToQ =
|
|
PerspectiveTransform::squareToQuadrilateral(x0p, y0p, x1p, y1p, x2p, y2p, x3p, y3p);
|
|
return sToQ.times(&qToS);
|
|
}
|
|
|
|
pub fn transform_points_single(&self, points: &mut [f32]) {
|
|
let a11 = self.a11;
|
|
let a12 = self.a12;
|
|
let a13 = self.a13;
|
|
let a21 = self.a21;
|
|
let a22 = self.a22;
|
|
let a23 = self.a23;
|
|
let a31 = self.a31;
|
|
let a32 = self.a32;
|
|
let a33 = self.a33;
|
|
let maxI = points.len() - 1; // points.length must be even
|
|
let mut i = 0;
|
|
while i < maxI {
|
|
// for (int i = 0; i < maxI; i += 2) {
|
|
let x = points[i];
|
|
let y = points[i + 1];
|
|
let denominator = a13 * x + a23 * y + a33;
|
|
points[i] = (a11 * x + a21 * y + a31) / denominator;
|
|
points[i + 1] = (a12 * x + a22 * y + a32) / denominator;
|
|
i += 2;
|
|
}
|
|
}
|
|
|
|
pub fn transform_points_double(&self, x_values: &mut [f32], y_valuess: &mut [f32]) {
|
|
let n = x_values.len();
|
|
for i in 0..n {
|
|
// for (int i = 0; i < n; i++) {
|
|
let x = x_values[i];
|
|
let y = y_valuess[i];
|
|
let denominator = self.a13 * x + self.a23 * y + self.a33;
|
|
x_values[i] = (self.a11 * x + self.a21 * y + self.a31) / denominator;
|
|
y_valuess[i] = (self.a12 * x + self.a22 * y + self.a32) / denominator;
|
|
}
|
|
}
|
|
|
|
pub fn squareToQuadrilateral(
|
|
x0: f32,
|
|
y0: f32,
|
|
x1: f32,
|
|
y1: f32,
|
|
x2: f32,
|
|
y2: f32,
|
|
x3: f32,
|
|
y3: f32,
|
|
) -> Self {
|
|
let dx3 = x0 - x1 + x2 - x3;
|
|
let dy3 = y0 - y1 + y2 - y3;
|
|
if dx3 == 0.0f32 && dy3 == 0.0f32 {
|
|
// Affine
|
|
return PerspectiveTransform::new(
|
|
x1 - x0,
|
|
x2 - x1,
|
|
x0,
|
|
y1 - y0,
|
|
y2 - y1,
|
|
y0,
|
|
0.0f32,
|
|
0.0f32,
|
|
1.0f32,
|
|
);
|
|
} else {
|
|
let dx1 = x1 - x2;
|
|
let dx2 = x3 - x2;
|
|
let dy1 = y1 - y2;
|
|
let dy2 = y3 - y2;
|
|
let denominator = dx1 * dy2 - dx2 * dy1;
|
|
let a13 = (dx3 * dy2 - dx2 * dy3) / denominator;
|
|
let a23 = (dx1 * dy3 - dx3 * dy1) / denominator;
|
|
return PerspectiveTransform::new(
|
|
x1 - x0 + a13 * x1,
|
|
x3 - x0 + a23 * x3,
|
|
x0,
|
|
y1 - y0 + a13 * y1,
|
|
y3 - y0 + a23 * y3,
|
|
y0,
|
|
a13,
|
|
a23,
|
|
1.0f32,
|
|
);
|
|
}
|
|
}
|
|
|
|
pub fn quadrilateralToSquare(
|
|
x0: f32,
|
|
y0: f32,
|
|
x1: f32,
|
|
y1: f32,
|
|
x2: f32,
|
|
y2: f32,
|
|
x3: f32,
|
|
y3: f32,
|
|
) -> Self {
|
|
// Here, the adjoint serves as the inverse
|
|
return PerspectiveTransform::squareToQuadrilateral(x0, y0, x1, y1, x2, y2, x3, y3)
|
|
.buildAdjoint();
|
|
}
|
|
|
|
fn buildAdjoint(&self) -> Self {
|
|
// Adjoint is the transpose of the cofactor matrix:
|
|
return PerspectiveTransform::new(
|
|
self.a22 * self.a33 - self.a23 * self.a32,
|
|
self.a23 * self.a31 - self.a21 * self.a33,
|
|
self.a21 * self.a32 - self.a22 * self.a31,
|
|
self.a13 * self.a32 - self.a12 * self.a33,
|
|
self.a11 * self.a33 - self.a13 * self.a31,
|
|
self.a12 * self.a31 - self.a11 * self.a32,
|
|
self.a12 * self.a23 - self.a13 * self.a22,
|
|
self.a13 * self.a21 - self.a11 * self.a23,
|
|
self.a11 * self.a22 - self.a12 * self.a21,
|
|
);
|
|
}
|
|
|
|
fn times(&self, other: &Self) -> Self {
|
|
return PerspectiveTransform::new(
|
|
self.a11 * other.a11 + self.a21 * other.a12 + self.a31 * other.a13,
|
|
self.a11 * other.a21 + self.a21 * other.a22 + self.a31 * other.a23,
|
|
self.a11 * other.a31 + self.a21 * other.a32 + self.a31 * other.a33,
|
|
self.a12 * other.a11 + self.a22 * other.a12 + self.a32 * other.a13,
|
|
self.a12 * other.a21 + self.a22 * other.a22 + self.a32 * other.a23,
|
|
self.a12 * other.a31 + self.a22 * other.a32 + self.a32 * other.a33,
|
|
self.a13 * other.a11 + self.a23 * other.a12 + self.a33 * other.a13,
|
|
self.a13 * other.a21 + self.a23 * other.a22 + self.a33 * other.a23,
|
|
self.a13 * other.a31 + self.a23 * other.a32 + self.a33 * other.a33,
|
|
);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* 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.List;
|
|
|
|
/**
|
|
* <p>Encapsulates the result of decoding a matrix of bits. This typically
|
|
* applies to 2D barcode formats. For now it contains the raw bytes obtained,
|
|
* as well as a String interpretation of those bytes, if applicable.</p>
|
|
*
|
|
* @author Sean Owen
|
|
*/
|
|
pub struct DecoderRXingResult {
|
|
rawBytes: Vec<u8>,
|
|
numBits: usize,
|
|
text: String,
|
|
byteSegments: Vec<u8>,
|
|
ecLevel: String,
|
|
errorsCorrected: u64,
|
|
erasures: u64,
|
|
other: Box<dyn Any>,
|
|
structuredAppendParity: i32,
|
|
structuredAppendSequenceNumber: i32,
|
|
symbologyModifier: u32,
|
|
}
|
|
|
|
impl DecoderRXingResult {
|
|
pub fn new(rawBytes: Vec<u8>, text: String, byteSegments: Vec<u8>, ecLevel: String) -> Self {
|
|
Self::with_all(rawBytes, text, byteSegments, ecLevel, -2, -2, 0)
|
|
}
|
|
|
|
pub fn with_symbology(
|
|
rawBytes: Vec<u8>,
|
|
text: String,
|
|
byteSegments: Vec<u8>,
|
|
ecLevel: String,
|
|
symbologyModifier: u32,
|
|
) -> Self {
|
|
Self::with_all(
|
|
rawBytes,
|
|
text,
|
|
byteSegments,
|
|
ecLevel,
|
|
-1,
|
|
-1,
|
|
symbologyModifier,
|
|
)
|
|
}
|
|
|
|
pub fn with_sa(
|
|
rawBytes: Vec<u8>,
|
|
text: String,
|
|
byteSegments: Vec<u8>,
|
|
ecLevel: String,
|
|
saSequence: i32,
|
|
saParity: i32,
|
|
) -> Self {
|
|
Self::with_all(
|
|
rawBytes,
|
|
text,
|
|
byteSegments,
|
|
ecLevel,
|
|
saSequence,
|
|
saParity,
|
|
0,
|
|
)
|
|
}
|
|
|
|
pub fn with_all(
|
|
rawBytes: Vec<u8>,
|
|
text: String,
|
|
byteSegments: Vec<u8>,
|
|
ecLevel: String,
|
|
saSequence: i32,
|
|
saParity: i32,
|
|
symbologyModifier: u32,
|
|
) -> Self {
|
|
let nb = rawBytes.len();
|
|
Self {
|
|
rawBytes,
|
|
numBits: nb,
|
|
text,
|
|
byteSegments,
|
|
ecLevel,
|
|
errorsCorrected: 0,
|
|
erasures: 0,
|
|
other: Box::new(false),
|
|
structuredAppendParity: saParity,
|
|
structuredAppendSequenceNumber: saSequence,
|
|
symbologyModifier,
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @return raw bytes representing the result, or {@code null} if not applicable
|
|
*/
|
|
pub fn getRawBytes(&self) -> &Vec<u8> {
|
|
&self.rawBytes
|
|
}
|
|
|
|
/**
|
|
* @return how many bits of {@link #getRawBytes()} are valid; typically 8 times its length
|
|
* @since 3.3.0
|
|
*/
|
|
pub fn getNumBits(&self) -> usize {
|
|
self.numBits
|
|
}
|
|
|
|
/**
|
|
* @param numBits overrides the number of bits that are valid in {@link #getRawBytes()}
|
|
* @since 3.3.0
|
|
*/
|
|
pub fn setNumBits(&mut self, numBits: usize) {
|
|
self.numBits = numBits;
|
|
}
|
|
|
|
/**
|
|
* @return text representation of the result
|
|
*/
|
|
pub fn getText(&self) -> &str {
|
|
&self.text
|
|
}
|
|
|
|
/**
|
|
* @return list of byte segments in the result, or {@code null} if not applicable
|
|
*/
|
|
pub fn getByteSegments(&self) -> &Vec<u8> {
|
|
&self.byteSegments
|
|
}
|
|
|
|
/**
|
|
* @return name of error correction level used, or {@code null} if not applicable
|
|
*/
|
|
pub fn getECLevel(&self) -> &str {
|
|
&self.ecLevel
|
|
}
|
|
|
|
/**
|
|
* @return number of errors corrected, or {@code null} if not applicable
|
|
*/
|
|
pub fn getErrorsCorrected(&self) -> u64 {
|
|
self.errorsCorrected
|
|
}
|
|
|
|
pub fn setErrorsCorrected(&mut self, errorsCorrected: u64) {
|
|
self.errorsCorrected = errorsCorrected;
|
|
}
|
|
|
|
/**
|
|
* @return number of erasures corrected, or {@code null} if not applicable
|
|
*/
|
|
pub fn getErasures(&self) -> u64 {
|
|
self.erasures
|
|
}
|
|
|
|
pub fn setErasures(&mut self, erasures: u64) {
|
|
self.erasures = erasures
|
|
}
|
|
|
|
/**
|
|
* @return arbitrary additional metadata
|
|
*/
|
|
pub fn getOther(&self) -> &Box<dyn Any> {
|
|
&self.other
|
|
}
|
|
|
|
pub fn setOther(&mut self, other: Box<dyn Any>) {
|
|
self.other = other
|
|
}
|
|
|
|
pub fn hasStructuredAppend(&self) -> bool {
|
|
self.structuredAppendParity >= 0 && self.structuredAppendSequenceNumber >= 0
|
|
}
|
|
|
|
pub fn getStructuredAppendParity(&self) -> i32 {
|
|
self.structuredAppendParity
|
|
}
|
|
|
|
pub fn getStructuredAppendSequenceNumber(&self) -> i32 {
|
|
self.structuredAppendSequenceNumber
|
|
}
|
|
|
|
pub fn getSymbologyModifier(&self) -> u32 {
|
|
self.symbologyModifier
|
|
}
|
|
}
|
|
|
|
/*
|
|
* 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.common;
|
|
|
|
// import java.io.ByteArrayOutputStream;
|
|
|
|
/**
|
|
* Class that lets one easily build an array of bytes by appending bits at a time.
|
|
*
|
|
* @author Sean Owen
|
|
*/
|
|
pub struct BitSourceBuilder {
|
|
output: Vec<u8>,
|
|
nextByte: u32,
|
|
bitsLeftInNextByte: u32,
|
|
}
|
|
|
|
impl BitSourceBuilder {
|
|
pub fn new() -> Self {
|
|
Self {
|
|
output: Vec::new(),
|
|
nextByte: 0,
|
|
bitsLeftInNextByte: 8,
|
|
}
|
|
}
|
|
|
|
pub fn write(&mut self, value: u32, numBits: u32) {
|
|
if numBits <= self.bitsLeftInNextByte {
|
|
self.nextByte <<= numBits;
|
|
self.nextByte |= value;
|
|
self.bitsLeftInNextByte -= numBits;
|
|
if self.bitsLeftInNextByte == 0 {
|
|
self.output.push(self.nextByte as u8);
|
|
self.nextByte = 0;
|
|
self.bitsLeftInNextByte = 8;
|
|
}
|
|
} else {
|
|
let bitsToWriteNow = self.bitsLeftInNextByte;
|
|
let numRestOfBits = numBits - bitsToWriteNow;
|
|
let mask = 0xFF >> (8 - bitsToWriteNow);
|
|
let valueToWriteNow = (value >> numRestOfBits) & mask;
|
|
self.write(valueToWriteNow, bitsToWriteNow);
|
|
self.write(value, numRestOfBits);
|
|
}
|
|
}
|
|
|
|
pub fn toByteArray(&mut self) -> &Vec<u8> {
|
|
if self.bitsLeftInNextByte < 8 {
|
|
self.write(0, self.bitsLeftInNextByte);
|
|
}
|
|
&self.output
|
|
}
|
|
}
|