porting more supporting qrcode files

This commit is contained in:
Henry Schimke
2022-10-01 09:54:30 -05:00
parent 2a80c95d75
commit afc7a20747
7 changed files with 1101 additions and 694 deletions

View File

@@ -1,157 +0,0 @@
/*
* 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.qrcode.decoder;
/**
* <p>Encapsulates a QR Code's format information, including the data mask used and
* error correction level.</p>
*
* @author Sean Owen
* @see DataMask
* @see ErrorCorrectionLevel
*/
final class FormatInformation {
private static final int FORMAT_INFO_MASK_QR = 0x5412;
/**
* See ISO 18004:2006, Annex C, Table C.1
*/
private static final int[][] FORMAT_INFO_DECODE_LOOKUP = {
{0x5412, 0x00},
{0x5125, 0x01},
{0x5E7C, 0x02},
{0x5B4B, 0x03},
{0x45F9, 0x04},
{0x40CE, 0x05},
{0x4F97, 0x06},
{0x4AA0, 0x07},
{0x77C4, 0x08},
{0x72F3, 0x09},
{0x7DAA, 0x0A},
{0x789D, 0x0B},
{0x662F, 0x0C},
{0x6318, 0x0D},
{0x6C41, 0x0E},
{0x6976, 0x0F},
{0x1689, 0x10},
{0x13BE, 0x11},
{0x1CE7, 0x12},
{0x19D0, 0x13},
{0x0762, 0x14},
{0x0255, 0x15},
{0x0D0C, 0x16},
{0x083B, 0x17},
{0x355F, 0x18},
{0x3068, 0x19},
{0x3F31, 0x1A},
{0x3A06, 0x1B},
{0x24B4, 0x1C},
{0x2183, 0x1D},
{0x2EDA, 0x1E},
{0x2BED, 0x1F},
};
private final ErrorCorrectionLevel errorCorrectionLevel;
private final byte dataMask;
private FormatInformation(int formatInfo) {
// Bits 3,4
errorCorrectionLevel = ErrorCorrectionLevel.forBits((formatInfo >> 3) & 0x03);
// Bottom 3 bits
dataMask = (byte) (formatInfo & 0x07);
}
static int numBitsDiffering(int a, int b) {
return Integer.bitCount(a ^ b);
}
/**
* @param maskedFormatInfo1 format info indicator, with mask still applied
* @param maskedFormatInfo2 second copy of same info; both are checked at the same time
* to establish best match
* @return information about the format it specifies, or {@code null}
* if doesn't seem to match any known pattern
*/
static FormatInformation decodeFormatInformation(int maskedFormatInfo1, int maskedFormatInfo2) {
FormatInformation formatInfo = doDecodeFormatInformation(maskedFormatInfo1, maskedFormatInfo2);
if (formatInfo != null) {
return formatInfo;
}
// Should return null, but, some QR codes apparently
// do not mask this info. Try again by actually masking the pattern
// first
return doDecodeFormatInformation(maskedFormatInfo1 ^ FORMAT_INFO_MASK_QR,
maskedFormatInfo2 ^ FORMAT_INFO_MASK_QR);
}
private static FormatInformation doDecodeFormatInformation(int maskedFormatInfo1, int maskedFormatInfo2) {
// Find the int in FORMAT_INFO_DECODE_LOOKUP with fewest bits differing
int bestDifference = Integer.MAX_VALUE;
int bestFormatInfo = 0;
for (int[] decodeInfo : FORMAT_INFO_DECODE_LOOKUP) {
int targetInfo = decodeInfo[0];
if (targetInfo == maskedFormatInfo1 || targetInfo == maskedFormatInfo2) {
// Found an exact match
return new FormatInformation(decodeInfo[1]);
}
int bitsDifference = numBitsDiffering(maskedFormatInfo1, targetInfo);
if (bitsDifference < bestDifference) {
bestFormatInfo = decodeInfo[1];
bestDifference = bitsDifference;
}
if (maskedFormatInfo1 != maskedFormatInfo2) {
// also try the other option
bitsDifference = numBitsDiffering(maskedFormatInfo2, targetInfo);
if (bitsDifference < bestDifference) {
bestFormatInfo = decodeInfo[1];
bestDifference = bitsDifference;
}
}
}
// Hamming distance of the 32 masked codes is 7, by construction, so <= 3 bits
// differing means we found a match
if (bestDifference <= 3) {
return new FormatInformation(bestFormatInfo);
}
return null;
}
ErrorCorrectionLevel getErrorCorrectionLevel() {
return errorCorrectionLevel;
}
byte getDataMask() {
return dataMask;
}
@Override
public int hashCode() {
return (errorCorrectionLevel.ordinal() << 3) | dataMask;
}
@Override
public boolean equals(Object o) {
if (!(o instanceof FormatInformation)) {
return false;
}
FormatInformation other = (FormatInformation) o;
return this.errorCorrectionLevel == other.errorCorrectionLevel &&
this.dataMask == other.dataMask;
}
}

View File

@@ -22,7 +22,7 @@ use crate::Exceptions;
*
* @author Sean Owen
*/
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
pub enum ErrorCorrectionLevel {
/** L = ~7% correction */
L, //0x01

View File

@@ -0,0 +1,174 @@
/*
* 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.
*/
use super::ErrorCorrectionLevel;
const FORMAT_INFO_MASK_QR: u32 = 0x5412;
/**
* See ISO 18004:2006, Annex C, Table C.1
*/
const FORMAT_INFO_DECODE_LOOKUP: [[u32; 2]; 32] = [
[0x5412, 0x00],
[0x5125, 0x01],
[0x5E7C, 0x02],
[0x5B4B, 0x03],
[0x45F9, 0x04],
[0x40CE, 0x05],
[0x4F97, 0x06],
[0x4AA0, 0x07],
[0x77C4, 0x08],
[0x72F3, 0x09],
[0x7DAA, 0x0A],
[0x789D, 0x0B],
[0x662F, 0x0C],
[0x6318, 0x0D],
[0x6C41, 0x0E],
[0x6976, 0x0F],
[0x1689, 0x10],
[0x13BE, 0x11],
[0x1CE7, 0x12],
[0x19D0, 0x13],
[0x0762, 0x14],
[0x0255, 0x15],
[0x0D0C, 0x16],
[0x083B, 0x17],
[0x355F, 0x18],
[0x3068, 0x19],
[0x3F31, 0x1A],
[0x3A06, 0x1B],
[0x24B4, 0x1C],
[0x2183, 0x1D],
[0x2EDA, 0x1E],
[0x2BED, 0x1F],
];
/**
* <p>Encapsulates a QR Code's format information, including the data mask used and
* error correction level.</p>
*
* @author Sean Owen
* @see DataMask
* @see ErrorCorrectionLevel
*/
#[derive(Hash, Eq, PartialEq)]
pub struct FormatInformation {
error_correction_level: ErrorCorrectionLevel,
data_mask: u8,
}
impl FormatInformation {
fn new(format_info: u8) -> Self {
// Bits 3,4
let errorCorrectionLevel =
ErrorCorrectionLevel::forBits((format_info >> 3) & 0x03).expect("pass in valid bits");
// Bottom 3 bits
let dataMask = format_info & 0x07;
Self {
error_correction_level: errorCorrectionLevel,
data_mask: dataMask,
}
}
pub fn numBitsDiffering(a: u32, b: u32) -> u32 {
(a ^ b).count_ones()
// return Integer.bitCount(a ^ b);
}
/**
* @param maskedFormatInfo1 format info indicator, with mask still applied
* @param maskedFormatInfo2 second copy of same info; both are checked at the same time
* to establish best match
* @return information about the format it specifies, or {@code null}
* if doesn't seem to match any known pattern
*/
fn decodeFormatInformation(
maskedFormatInfo1: u32,
maskedFormatInfo2: u32,
) -> FormatInformation {
let formatInfo = Self::doDecodeFormatInformation(maskedFormatInfo1, maskedFormatInfo2);
if formatInfo.is_some() {
return formatInfo.unwrap();
}
// Should return null, but, some QR codes apparently
// do not mask this info. Try again by actually masking the pattern
// first
return Self::doDecodeFormatInformation(
maskedFormatInfo1 ^ FORMAT_INFO_MASK_QR,
maskedFormatInfo2 ^ FORMAT_INFO_MASK_QR,
)
.unwrap();
}
fn doDecodeFormatInformation(
masked_format_info1: u32,
masked_format_info2: u32,
) -> Option<FormatInformation> {
// Find the int in FORMAT_INFO_DECODE_LOOKUP with fewest bits differing
let best_difference = u32::MAX;
let best_format_info = 0;
for decodeInfo in FORMAT_INFO_DECODE_LOOKUP {
// for (int[] decodeInfo : FORMAT_INFO_DECODE_LOOKUP) {
let targetInfo = decodeInfo[0];
if targetInfo == masked_format_info1 || targetInfo == masked_format_info2 {
// Found an exact match
return Some(FormatInformation::new(decodeInfo[1] as u8));
}
let bits_difference = Self::numBitsDiffering(masked_format_info1, targetInfo);
if bits_difference < best_difference {
best_format_info = decodeInfo[1] as u8;
best_difference = bits_difference;
}
if masked_format_info1 != masked_format_info2 {
// also try the other option
bits_difference = Self::numBitsDiffering(masked_format_info2, targetInfo);
if (bits_difference < best_difference) {
best_format_info = decodeInfo[1] as u8;
best_difference = bits_difference;
}
}
}
// Hamming distance of the 32 masked codes is 7, by construction, so <= 3 bits
// differing means we found a match
if best_difference <= 3 {
return Some(FormatInformation::new(best_format_info));
}
None
}
pub fn getErrorCorrectionLevel(&self) -> &ErrorCorrectionLevel {
&self.error_correction_level
}
pub fn getDataMask(&self) -> u8 {
self.data_mask
}
// @Override
// public int hashCode() {
// return (errorCorrectionLevel.ordinal() << 3) | dataMask;
// }
// @Override
// public boolean equals(Object o) {
// if (!(o instanceof FormatInformation)) {
// return false;
// }
// FormatInformation other = (FormatInformation) o;
// return this.errorCorrectionLevel == other.errorCorrectionLevel &&
// this.dataMask == other.dataMask;
// }
}

View File

@@ -1,10 +1,12 @@
mod version;
mod mode;
mod error_correction_level;
mod format_information;
#[cfg(test)]
mod ErrorCorrectionLevelTestCase;
pub use version::*;
pub use mode::*;
pub use error_correction_level::*;
pub use error_correction_level::*;
pub use format_information::*;

View File

@@ -16,6 +16,8 @@
use crate::Exceptions;
use super::Version;
/**
* <p>See ISO 18004:2006, 6.4.1, Tables 2 and 3. This enum encapsulates the various modes in which
* data can be encoded to bits in the QR code standard.</p>

File diff suppressed because it is too large Load Diff