mirror of
https://github.com/starovoid/rxing.git
synced 2026-07-26 04:12:34 +00:00
non passing aztec decoder port
This commit is contained in:
@@ -1,226 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2014 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.aztec.decoder;
|
|
||||||
|
|
||||||
import com.google.zxing.aztec.encoder.EncoderTest;
|
|
||||||
|
|
||||||
import com.google.zxing.FormatException;
|
|
||||||
import com.google.zxing.RXingResultPoint;
|
|
||||||
import com.google.zxing.aztec.AztecDetectorRXingResult;
|
|
||||||
import com.google.zxing.common.BitArray;
|
|
||||||
import com.google.zxing.common.BitMatrix;
|
|
||||||
import com.google.zxing.common.DecoderRXingResult;
|
|
||||||
import org.junit.Test;
|
|
||||||
import org.junit.Assert;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests {@link Decoder}.
|
|
||||||
*/
|
|
||||||
public final class DecoderTest extends Assert {
|
|
||||||
|
|
||||||
private static final RXingResultPoint[] NO_POINTS = new RXingResultPoint[0];
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testHighLevelDecode() throws FormatException {
|
|
||||||
// no ECI codes
|
|
||||||
testHighLevelDecodeString("A. b.",
|
|
||||||
// 'A' P/S '. ' L/L b D/L '.'
|
|
||||||
"...X. ..... ...XX XXX.. ...XX XXXX. XX.X");
|
|
||||||
|
|
||||||
// initial ECI code 26 (switch to UTF-8)
|
|
||||||
testHighLevelDecodeString("Ça",
|
|
||||||
// P/S FLG(n) 2 '2' '6' B/S 2 0xc3 0x87 L/L 'a'
|
|
||||||
"..... ..... .X. .X.. X... XXXXX ...X. XX....XX X....XXX XXX.. ...X.");
|
|
||||||
|
|
||||||
// initial character without ECI (must be interpreted as ISO_8859_1)
|
|
||||||
// followed by ECI code 26 (= UTF-8) and UTF-8 text
|
|
||||||
testHighLevelDecodeString("±Ça",
|
|
||||||
// B/S 1 0xb1 P/S FLG(n) 2 '2' '6' B/S 2 0xc3 0x87 L/L 'a'
|
|
||||||
"XXXXX ....X X.XX...X ..... ..... .X. .X.. X... XXXXX ...X. XX....XX X....XXX XXX.. ...X.");
|
|
||||||
|
|
||||||
// GS1 data
|
|
||||||
testHighLevelDecodeString("101233742",
|
|
||||||
// P/S FLG(n) 0 D/L 1 0 1 2 3 P/S FLG(n) 0 3 7 4 2
|
|
||||||
"..... ..... ... XXXX. ..XX ..X. ..XX .X.. .X.X .... ..... ... .X.X X..X .XX. .X..");
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void testHighLevelDecodeString(String expectedString, String b) throws FormatException {
|
|
||||||
BitArray bits = EncoderTest.toBitArray(EncoderTest.stripSpace(b));
|
|
||||||
assertEquals("highLevelDecode() failed for input bits: " + b,
|
|
||||||
expectedString, Decoder.highLevelDecode(EncoderTest.toBooleanArray(bits)));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testAztecRXingResult() throws FormatException {
|
|
||||||
BitMatrix matrix = BitMatrix.parse(
|
|
||||||
"X X X X X X X X X X X X X X \n" +
|
|
||||||
"X X X X X X X X X X X X X X X \n" +
|
|
||||||
" X X X X X X X X X X X X \n" +
|
|
||||||
" X X X X X X X X X X \n" +
|
|
||||||
" X X X X X X X X \n" +
|
|
||||||
" X X X X X X X X X X X X X X X X X X \n" +
|
|
||||||
" X X X X X X X X X \n" +
|
|
||||||
" X X X X X X X X X X X X X X X X X \n" +
|
|
||||||
" X X X X X X X X X \n" +
|
|
||||||
" X X X X X X X X X X X X X X X X \n" +
|
|
||||||
" X X X X X X X X X X X X \n" +
|
|
||||||
" X X X X X X X X X X X \n" +
|
|
||||||
" X X X X X X X X X X X X \n" +
|
|
||||||
" X X X X X X X X X X X X X X X X X \n" +
|
|
||||||
"X X X X X X X X X X X \n" +
|
|
||||||
" X X X X X X X X X X X X X X \n" +
|
|
||||||
" X X X X X X X X \n" +
|
|
||||||
" X X X X X X X X X X X X X X X X X X X \n" +
|
|
||||||
"X X X X X X X X X \n" +
|
|
||||||
"X X X X X X X X X X X X X X X \n" +
|
|
||||||
"X X X X X X X X X X X X \n" +
|
|
||||||
"X X X X X X X X X X X X X X \n" +
|
|
||||||
" X X X X X X X X X X X X X \n",
|
|
||||||
"X ", " ");
|
|
||||||
AztecDetectorRXingResult r = new AztecDetectorRXingResult(matrix, NO_POINTS, false, 30, 2);
|
|
||||||
DecoderRXingResult result = new Decoder().decode(r);
|
|
||||||
assertEquals("88888TTTTTTTTTTTTTTTTTTTTTTTTTTTTTT", result.getText());
|
|
||||||
assertArrayEquals(
|
|
||||||
new byte[] {-11, 85, 85, 117, 107, 90, -42, -75, -83, 107,
|
|
||||||
90, -42, -75, -83, 107, 90, -42, -75, -83, 107,
|
|
||||||
90, -42, -80},
|
|
||||||
result.getRawBytes());
|
|
||||||
assertEquals(180, result.getNumBits());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testAztecRXingResultECI() throws FormatException {
|
|
||||||
BitMatrix matrix = BitMatrix.parse(
|
|
||||||
" X X X X X X \n" +
|
|
||||||
" X X X X X X X X X X X X \n" +
|
|
||||||
" X X X X \n" +
|
|
||||||
" X X X X X X X X X X X X X X X X X \n" +
|
|
||||||
" X X \n" +
|
|
||||||
" X X X X X X X X X X X X \n" +
|
|
||||||
" X X X X X X X X \n" +
|
|
||||||
" X X X X X X X X X X X X \n" +
|
|
||||||
" X X X X X X X X \n" +
|
|
||||||
" X X X X X X X X X \n" +
|
|
||||||
"X X X X X X X X X \n" +
|
|
||||||
" X X X X X X X X X X X X \n" +
|
|
||||||
" X X X X X X \n" +
|
|
||||||
" X X X X X X X X X X X X X \n" +
|
|
||||||
" X X X \n" +
|
|
||||||
"X X X X X X X X X X X X X X X X X \n" +
|
|
||||||
"X X X X X X X X X \n" +
|
|
||||||
" X X X X X X X X X X X \n" +
|
|
||||||
"X X X X X X X X \n",
|
|
||||||
"X ", " ");
|
|
||||||
AztecDetectorRXingResult r = new AztecDetectorRXingResult(matrix, NO_POINTS, false, 15, 1);
|
|
||||||
DecoderRXingResult result = new Decoder().decode(r);
|
|
||||||
assertEquals("Français", result.getText());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test(expected = FormatException.class)
|
|
||||||
public void testDecodeTooManyErrors() throws FormatException {
|
|
||||||
BitMatrix matrix = BitMatrix.parse(""
|
|
||||||
+ "X X . X . . . X X . . . X . . X X X . X . X X X X X . \n"
|
|
||||||
+ "X X . . X X . . . . . X X . . . X X . . . X . X . . X \n"
|
|
||||||
+ "X . . . X X . . X X X . X X . X X X X . X X . . X . . \n"
|
|
||||||
+ ". . . . X . X X . . X X . X X . X . X X X X . X . . X \n"
|
|
||||||
+ "X X X . . X X X X X . . . . . X X . . . X . X . X . X \n"
|
|
||||||
+ "X X . . . . . . . . X . . . X . X X X . X . . X . . . \n"
|
|
||||||
+ "X X . . X . . . . . X X . . . . . X . . . . X . . X X \n"
|
|
||||||
+ ". . . X . X . X . . . . . X X X X X X . . . . . . X X \n"
|
|
||||||
+ "X . . . X . X X X X X X . . X X X . X . X X X X X X . \n"
|
|
||||||
+ "X . . X X X . X X X X X X X X X X X X X . . . X . X X \n"
|
|
||||||
+ ". . . . X X . . . X . . . . . . . X X . . . X X . X . \n"
|
|
||||||
+ ". . . X X X . . X X . X X X X X . X . . X . . . . . . \n"
|
|
||||||
+ "X . . . . X . X . X . X . . . X . X . X X . X X . X X \n"
|
|
||||||
+ "X . X . . X . X . X . X . X . X . X . . . . . X . X X \n"
|
|
||||||
+ "X . X X X . . X . X . X . . . X . X . X X X . . . X X \n"
|
|
||||||
+ "X X X X X X X X . X . X X X X X . X . X . X . X X X . \n"
|
|
||||||
+ ". . . . . . . X . X . . . . . . . X X X X . . . X X X \n"
|
|
||||||
+ "X X . . X . . X . X X X X X X X X X X X X X . . X . X \n"
|
|
||||||
+ "X X X . X X X X . . X X X X . . X . . . . X . . X X X \n"
|
|
||||||
+ ". . . . X . X X X . . . . X X X X . . X X X X . . . . \n"
|
|
||||||
+ ". . X . . X . X . . . X . X X . X X . X . . . X . X . \n"
|
|
||||||
+ "X X . . X . . X X X X X X X . . X . X X X X X X X . . \n"
|
|
||||||
+ "X . X X . . X X . . . . . X . . . . . . X X . X X X . \n"
|
|
||||||
+ "X . . X X . . X X . X . X . . . . X . X . . X . . X . \n"
|
|
||||||
+ "X . X . X . . X . X X X X X X X X . X X X X . . X X . \n"
|
|
||||||
+ "X X X X . . . X . . X X X . X X . . X . . . . X X X . \n"
|
|
||||||
+ "X X . X . X . . . X . X . . . . X X . X . . X X . . . \n",
|
|
||||||
"X ", ". ");
|
|
||||||
AztecDetectorRXingResult r = new AztecDetectorRXingResult(matrix, NO_POINTS, true, 16, 4);
|
|
||||||
new Decoder().decode(r);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test(expected = FormatException.class)
|
|
||||||
public void testDecodeTooManyErrors2() throws FormatException {
|
|
||||||
BitMatrix matrix = BitMatrix.parse(""
|
|
||||||
+ ". X X . . X . X X . . . X . . X X X . . . X X . X X . \n"
|
|
||||||
+ "X X . X X . . X . . . X X . . . X X . X X X . X . X X \n"
|
|
||||||
+ ". . . . X . . . X X X . X X . X X X X . X X . . X . . \n"
|
|
||||||
+ "X . X X . . X . . . X X . X X . X . X X . . . . . X . \n"
|
|
||||||
+ "X X . X . . X . X X . . . . . X X . . . . . X . . . X \n"
|
|
||||||
+ "X . . X . . . . . . X . . . X . X X X X X X X . . . X \n"
|
|
||||||
+ "X . . X X . . X . . X X . . . . . X . . . . . X X X . \n"
|
|
||||||
+ ". . X X X X . X . . . . . X X X X X X . . . . . . X X \n"
|
|
||||||
+ "X . . . X . X X X X X X . . X X X . X . X X X X X X . \n"
|
|
||||||
+ "X . . X X X . X X X X X X X X X X X X X . . . X . X X \n"
|
|
||||||
+ ". . . . X X . . . X . . . . . . . X X . . . X X . X . \n"
|
|
||||||
+ ". . . X X X . . X X . X X X X X . X . . X . . . . . . \n"
|
|
||||||
+ "X . . . . X . X . X . X . . . X . X . X X . X X . X X \n"
|
|
||||||
+ "X . X . . X . X . X . X . X . X . X . . . . . X . X X \n"
|
|
||||||
+ "X . X X X . . X . X . X . . . X . X . X X X . . . X X \n"
|
|
||||||
+ "X X X X X X X X . X . X X X X X . X . X . X . X X X . \n"
|
|
||||||
+ ". . . . . . . X . X . . . . . . . X X X X . . . X X X \n"
|
|
||||||
+ "X X . . X . . X . X X X X X X X X X X X X X . . X . X \n"
|
|
||||||
+ "X X X . X X X X . . X X X X . . X . . . . X . . X X X \n"
|
|
||||||
+ ". . X X X X X . X . . . . X X X X . . X X X . X . X . \n"
|
|
||||||
+ ". . X X . X . X . . . X . X X . X X . . . . X X . . . \n"
|
|
||||||
+ "X . . . X . X . X X X X X X . . X . X X X X X . X . . \n"
|
|
||||||
+ ". X . . . X X X . . . . . X . . . . . X X X X X . X . \n"
|
|
||||||
+ "X . . X . X X X X . X . X . . . . X . X X . X . . X . \n"
|
|
||||||
+ "X . . . X X . X . X X X X X X X X . X X X X . . X X . \n"
|
|
||||||
+ ". X X X X . . X . . X X X . X X . . X . . . . X X X . \n"
|
|
||||||
+ "X X . . . X X . . X . X . . . . X X . X . . X . X . X \n",
|
|
||||||
"X ", ". ");
|
|
||||||
AztecDetectorRXingResult r = new AztecDetectorRXingResult(matrix, NO_POINTS, true, 16, 4);
|
|
||||||
new Decoder().decode(r);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testRawBytes() {
|
|
||||||
boolean[] bool0 = {};
|
|
||||||
boolean[] bool1 = { true };
|
|
||||||
boolean[] bool7 = { true, false, true, false, true, false, true };
|
|
||||||
boolean[] bool8 = { true, false, true, false, true, false, true, false };
|
|
||||||
boolean[] bool9 = { true, false, true, false, true, false, true, false,
|
|
||||||
true };
|
|
||||||
boolean[] bool16 = { false, true, true, false, false, false, true, true,
|
|
||||||
true, true, false, false, false, false, false, true };
|
|
||||||
byte[] byte0 = {};
|
|
||||||
byte[] byte1 = { -128 };
|
|
||||||
byte[] byte7 = { -86 };
|
|
||||||
byte[] byte8 = { -86 };
|
|
||||||
byte[] byte9 = { -86, -128 };
|
|
||||||
byte[] byte16 = { 99, -63 };
|
|
||||||
|
|
||||||
assertArrayEquals(byte0, Decoder.convertBoolArrayToByteArray(bool0));
|
|
||||||
assertArrayEquals(byte1, Decoder.convertBoolArrayToByteArray(bool1));
|
|
||||||
assertArrayEquals(byte7, Decoder.convertBoolArrayToByteArray(bool7));
|
|
||||||
assertArrayEquals(byte8, Decoder.convertBoolArrayToByteArray(bool8));
|
|
||||||
assertArrayEquals(byte9, Decoder.convertBoolArrayToByteArray(bool9));
|
|
||||||
assertArrayEquals(byte16, Decoder.convertBoolArrayToByteArray(bool16));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,58 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2010 ZXing authors
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.google.zxing.aztec;
|
|
||||||
|
|
||||||
import com.google.zxing.RXingResultPoint;
|
|
||||||
import com.google.zxing.common.BitMatrix;
|
|
||||||
import com.google.zxing.common.DetectorRXingResult;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>Extends {@link DetectorRXingResult} with more information specific to the Aztec format,
|
|
||||||
* like the number of layers and whether it's compact.</p>
|
|
||||||
*
|
|
||||||
* @author Sean Owen
|
|
||||||
*/
|
|
||||||
public final class AztecDetectorRXingResult extends DetectorRXingResult {
|
|
||||||
|
|
||||||
private final boolean compact;
|
|
||||||
private final int nbDatablocks;
|
|
||||||
private final int nbLayers;
|
|
||||||
|
|
||||||
public AztecDetectorRXingResult(BitMatrix bits,
|
|
||||||
RXingResultPoint[] points,
|
|
||||||
boolean compact,
|
|
||||||
int nbDatablocks,
|
|
||||||
int nbLayers) {
|
|
||||||
super(bits, points);
|
|
||||||
this.compact = compact;
|
|
||||||
this.nbDatablocks = nbDatablocks;
|
|
||||||
this.nbLayers = nbLayers;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getNbLayers() {
|
|
||||||
return nbLayers;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getNbDatablocks() {
|
|
||||||
return nbDatablocks;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isCompact() {
|
|
||||||
return compact;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
80
src/aztec/AztecDetectorResult.rs
Normal file
80
src/aztec/AztecDetectorResult.rs
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010 ZXing authors
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// package com.google.zxing.aztec;
|
||||||
|
|
||||||
|
// import com.google.zxing.RXingResultPoint;
|
||||||
|
// import com.google.zxing.common.BitMatrix;
|
||||||
|
// import com.google.zxing.common.DetectorRXingResult;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
common::{BitMatrix, DetectorRXingResult},
|
||||||
|
RXingResultPoint,
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Extends {@link DetectorRXingResult} with more information specific to the Aztec format,
|
||||||
|
* like the number of layers and whether it's compact.</p>
|
||||||
|
*
|
||||||
|
* @author Sean Owen
|
||||||
|
*/
|
||||||
|
pub struct AztecDetectorRXingResult {
|
||||||
|
bits: BitMatrix,
|
||||||
|
points: Vec<RXingResultPoint>,
|
||||||
|
compact: bool,
|
||||||
|
nbDatablocks: u32,
|
||||||
|
nbLayers: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DetectorRXingResult for AztecDetectorRXingResult {
|
||||||
|
fn getBits(&self) -> &BitMatrix {
|
||||||
|
&self.bits
|
||||||
|
}
|
||||||
|
|
||||||
|
fn getPoints(&self) -> &Vec<RXingResultPoint> {
|
||||||
|
&self.points
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AztecDetectorRXingResult {
|
||||||
|
pub fn new(
|
||||||
|
bits: BitMatrix,
|
||||||
|
points: Vec<RXingResultPoint>,
|
||||||
|
compact: bool,
|
||||||
|
nbDatablocks: u32,
|
||||||
|
nbLayers: u32,
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
bits,
|
||||||
|
points,
|
||||||
|
compact,
|
||||||
|
nbDatablocks,
|
||||||
|
nbLayers,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn getNbLayers(&self) -> u32 {
|
||||||
|
self.nbLayers
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn getNbDatablocks(&self) -> u32 {
|
||||||
|
self.nbDatablocks
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn isCompact(&self) -> bool {
|
||||||
|
self.compact
|
||||||
|
}
|
||||||
|
}
|
||||||
285
src/aztec/DecoderTest.rs
Normal file
285
src/aztec/DecoderTest.rs
Normal file
@@ -0,0 +1,285 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2014 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.aztec.decoder;
|
||||||
|
|
||||||
|
// import com.google.zxing.aztec.encoder.EncoderTest;
|
||||||
|
|
||||||
|
// import com.google.zxing.FormatException;
|
||||||
|
// import com.google.zxing.RXingResultPoint;
|
||||||
|
// import com.google.zxing.aztec.AztecDetectorRXingResult;
|
||||||
|
// import com.google.zxing.common.BitArray;
|
||||||
|
// import com.google.zxing.common.BitMatrix;
|
||||||
|
// import com.google.zxing.common.DecoderRXingResult;
|
||||||
|
// import org.junit.Test;
|
||||||
|
// import org.junit.Assert;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
aztec::shared_test_methods::{stripSpace, toBitArray, toBooleanArray},
|
||||||
|
common::BitMatrix,
|
||||||
|
RXingResultPoint,
|
||||||
|
};
|
||||||
|
|
||||||
|
use super::{decoder, AztecDetectorResult::AztecDetectorRXingResult};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests {@link Decoder}.
|
||||||
|
*/
|
||||||
|
|
||||||
|
const NO_POINTS: &[RXingResultPoint] = &[RXingResultPoint { x: 0.0, y: 0.0 }; 0];
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn testHighLevelDecode() {
|
||||||
|
// no ECI codes
|
||||||
|
testHighLevelDecodeString(
|
||||||
|
"A. b.",
|
||||||
|
// 'A' P/S '. ' L/L b D/L '.'
|
||||||
|
"...X. ..... ...XX XXX.. ...XX XXXX. XX.X",
|
||||||
|
);
|
||||||
|
|
||||||
|
// initial ECI code 26 (switch to UTF-8)
|
||||||
|
testHighLevelDecodeString(
|
||||||
|
"Ça",
|
||||||
|
// P/S FLG(n) 2 '2' '6' B/S 2 0xc3 0x87 L/L 'a'
|
||||||
|
"..... ..... .X. .X.. X... XXXXX ...X. XX....XX X....XXX XXX.. ...X.",
|
||||||
|
);
|
||||||
|
|
||||||
|
// initial character without ECI (must be interpreted as ISO_8859_1)
|
||||||
|
// followed by ECI code 26 (= UTF-8) and UTF-8 text
|
||||||
|
testHighLevelDecodeString(
|
||||||
|
"±Ça",
|
||||||
|
// B/S 1 0xb1 P/S FLG(n) 2 '2' '6' B/S 2 0xc3 0x87 L/L 'a'
|
||||||
|
"XXXXX ....X X.XX...X ..... ..... .X. .X.. X... XXXXX ...X. XX....XX X....XXX XXX.. ...X.",
|
||||||
|
);
|
||||||
|
|
||||||
|
// GS1 data
|
||||||
|
testHighLevelDecodeString(
|
||||||
|
"101233742",
|
||||||
|
// P/S FLG(n) 0 D/L 1 0 1 2 3 P/S FLG(n) 0 3 7 4 2
|
||||||
|
"..... ..... ... XXXX. ..XX ..X. ..XX .X.. .X.X .... ..... ... .X.X X..X .XX. .X..",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn testHighLevelDecodeString(expectedString: &str, b: &str) {
|
||||||
|
let bits = toBitArray(&stripSpace(b));
|
||||||
|
assert_eq!(
|
||||||
|
expectedString,
|
||||||
|
decoder::highLevelDecode(&toBooleanArray(&bits)).expect("highLevelDecode Failed"),
|
||||||
|
"highLevelDecode() failed for input bits: {}",
|
||||||
|
b
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn testAztecRXingResult() {
|
||||||
|
let matrix = BitMatrix::parse_strings(
|
||||||
|
r"X X X X X X X X X X X X X X
|
||||||
|
X X X X X X X X X X X X X X X
|
||||||
|
X X X X X X X X X X X X
|
||||||
|
X X X X X X X X X X
|
||||||
|
X X X X X X X X
|
||||||
|
X X X X X X X X X X X X X X X X X X
|
||||||
|
X X X X X X X X X
|
||||||
|
X X X X X X X X X X X X X X X X X
|
||||||
|
X X X X X X X X X
|
||||||
|
X X X X X X X X X X X X X X X X
|
||||||
|
X X X X X X X X X X X X
|
||||||
|
X X X X X X X X X X X
|
||||||
|
X X X X X X X X X X X X
|
||||||
|
X X X X X X X X X X X X X X X X X
|
||||||
|
X X X X X X X X X X X
|
||||||
|
X X X X X X X X X X X X X X
|
||||||
|
X X X X X X X X
|
||||||
|
X X X X X X X X X X X X X X X X X X X
|
||||||
|
X X X X X X X X X
|
||||||
|
X X X X X X X X X X X X X X X
|
||||||
|
X X X X X X X X X X X X
|
||||||
|
X X X X X X X X X X X X X X
|
||||||
|
X X X X X X X X X X X X X
|
||||||
|
",
|
||||||
|
"X ",
|
||||||
|
" ",
|
||||||
|
)
|
||||||
|
.expect("Bitmatrix should init");
|
||||||
|
let r = AztecDetectorRXingResult::new(matrix, NO_POINTS.to_vec(), false, 30, 2);
|
||||||
|
let result = decoder::decode(&r).expect("decoder should init");
|
||||||
|
assert_eq!("88888TTTTTTTTTTTTTTTTTTTTTTTTTTTTTT", result.getText());
|
||||||
|
assert_eq!(
|
||||||
|
&vec![
|
||||||
|
-11i8 as u8,
|
||||||
|
85,
|
||||||
|
85,
|
||||||
|
117,
|
||||||
|
107,
|
||||||
|
90,
|
||||||
|
-42i8 as u8,
|
||||||
|
-75i8 as u8,
|
||||||
|
-83i8 as u8,
|
||||||
|
107,
|
||||||
|
90,
|
||||||
|
-42i8 as u8,
|
||||||
|
-75i8 as u8,
|
||||||
|
-83i8 as u8,
|
||||||
|
107,
|
||||||
|
90,
|
||||||
|
-42i8 as u8,
|
||||||
|
-75i8 as u8,
|
||||||
|
-83i8 as u8,
|
||||||
|
107,
|
||||||
|
90,
|
||||||
|
-42i8 as u8,
|
||||||
|
-80i8 as u8
|
||||||
|
],
|
||||||
|
result.getRawBytes()
|
||||||
|
);
|
||||||
|
assert_eq!(180, result.getNumBits());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn testAztecRXingResultECI() {
|
||||||
|
let matrix = BitMatrix::parse_strings(
|
||||||
|
r" X X X X X X
|
||||||
|
X X X X X X X X X X X X
|
||||||
|
X X X X
|
||||||
|
X X X X X X X X X X X X X X X X X
|
||||||
|
X X
|
||||||
|
X X X X X X X X X X X X
|
||||||
|
X X X X X X X X
|
||||||
|
X X X X X X X X X X X X
|
||||||
|
X X X X X X X X
|
||||||
|
X X X X X X X X X
|
||||||
|
X X X X X X X X X
|
||||||
|
X X X X X X X X X X X X
|
||||||
|
X X X X X X
|
||||||
|
X X X X X X X X X X X X X
|
||||||
|
X X X
|
||||||
|
X X X X X X X X X X X X X X X X X
|
||||||
|
X X X X X X X X X
|
||||||
|
X X X X X X X X X X X
|
||||||
|
X X X X X X X X ",
|
||||||
|
"X ",
|
||||||
|
" ",
|
||||||
|
)
|
||||||
|
.expect("string parse success");
|
||||||
|
let r = AztecDetectorRXingResult::new(matrix, NO_POINTS.to_vec(), false, 15, 1);
|
||||||
|
let result = decoder::decode(&r).expect("decode success");
|
||||||
|
assert_eq!("Français", result.getText());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[should_panic]
|
||||||
|
fn testDecodeTooManyErrors() {
|
||||||
|
let matrix = BitMatrix::parse_strings(
|
||||||
|
r"
|
||||||
|
X X . X . . . X X . . . X . . X X X . X . X X X X X .
|
||||||
|
X X . . X X . . . . . X X . . . X X . . . X . X . . X
|
||||||
|
X . . . X X . . X X X . X X . X X X X . X X . . X . .
|
||||||
|
. . . . X . X X . . X X . X X . X . X X X X . X . . X
|
||||||
|
X X X . . X X X X X . . . . . X X . . . X . X . X . X
|
||||||
|
X X . . . . . . . . X . . . X . X X X . X . . X . . .
|
||||||
|
X X . . X . . . . . X X . . . . . X . . . . X . . X X \
|
||||||
|
. . . X . X . X . . . . . X X X X X X . . . . . . X X
|
||||||
|
X . . . X . X X X X X X . . X X X . X . X X X X X X .
|
||||||
|
X . . X X X . X X X X X X X X X X X X X . . . X . X X
|
||||||
|
. . . . X X . . . X . . . . . . . X X . . . X X . X .
|
||||||
|
. . . X X X . . X X . X X X X X . X . . X . . . . . .
|
||||||
|
X . . . . X . X . X . X . . . X . X . X X . X X . X X
|
||||||
|
X . X . . X . X . X . X . X . X . X . . . . . X . X X
|
||||||
|
X . X X X . . X . X . X . . . X . X . X X X . . . X X
|
||||||
|
X X X X X X X X . X . X X X X X . X . X . X . X X X .
|
||||||
|
. . . . . . . X . X . . . . . . . X X X X . . . X X X
|
||||||
|
X X . . X . . X . X X X X X X X X X X X X X . . X . X
|
||||||
|
X X X . X X X X . . X X X X . . X . . . . X . . X X X
|
||||||
|
. . . . X . X X X . . . . X X X X . . X X X X . . . .
|
||||||
|
. . X . . X . X . . . X . X X . X X . X . . . X . X .
|
||||||
|
X X . . X . . X X X X X X X . . X . X X X X X X X . .
|
||||||
|
X . X X . . X X . . . . . X . . . . . . X X . X X X .
|
||||||
|
X . . X X . . X X . X . X . . . . X . X . . X . . X .
|
||||||
|
X . X . X . . X . X X X X X X X X . X X X X . . X X .
|
||||||
|
X X X X . . . X . . X X X . X X . . X . . . . X X X .
|
||||||
|
X X . X . X . . . X . X . . . . X X . X . . X X . . . ",
|
||||||
|
"X ",
|
||||||
|
". ",
|
||||||
|
)
|
||||||
|
.expect("parse string success");
|
||||||
|
let r = AztecDetectorRXingResult::new(matrix, NO_POINTS.to_vec(), true, 16, 4);
|
||||||
|
decoder::decode(&r);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[should_panic]
|
||||||
|
fn testDecodeTooManyErrors2() {
|
||||||
|
let matrix = BitMatrix::parse_strings(
|
||||||
|
r"
|
||||||
|
. X X . . X . X X . . . X . . X X X . . . X X . X X .
|
||||||
|
X X . X X . . X . . . X X . . . X X . X X X . X . X X
|
||||||
|
. . . . X . . . X X X . X X . X X X X . X X . . X . .
|
||||||
|
X . X X . . X . . . X X . X X . X . X X . . . . . X .
|
||||||
|
X X . X . . X . X X . . . . . X X . . . . . X . . . X
|
||||||
|
X . . X . . . . . . X . . . X . X X X X X X X . . . X
|
||||||
|
X . . X X . . X . . X X . . . . . X . . . . . X X X .
|
||||||
|
. . X X X X . X . . . . . X X X X X X . . . . . . X X
|
||||||
|
X . . . X . X X X X X X . . X X X . X . X X X X X X .
|
||||||
|
X . . X X X . X X X X X X X X X X X X X . . . X . X X
|
||||||
|
. . . . X X . . . X . . . . . . . X X . . . X X . X .
|
||||||
|
. . . X X X . . X X . X X X X X . X . . X . . . . . .
|
||||||
|
X . . . . X . X . X . X . . . X . X . X X . X X . X X
|
||||||
|
X . X . . X . X . X . X . X . X . X . . . . . X . X X
|
||||||
|
X . X X X . . X . X . X . . . X . X . X X X . . . X X
|
||||||
|
X X X X X X X X . X . X X X X X . X . X . X . X X X .
|
||||||
|
. . . . . . . X . X . . . . . . . X X X X . . . X X X
|
||||||
|
X X . . X . . X . X X X X X X X X X X X X X . . X . X
|
||||||
|
X X X . X X X X . . X X X X . . X . . . . X . . X X X
|
||||||
|
. . X X X X X . X . . . . X X X X . . X X X . X . X .
|
||||||
|
. . X X . X . X . . . X . X X . X X . . . . X X . . .
|
||||||
|
X . . . X . X . X X X X X X . . X . X X X X X . X . .
|
||||||
|
. X . . . X X X . . . . . X . . . . . X X X X X . X .
|
||||||
|
X . . X . X X X X . X . X . . . . X . X X . X . . X .
|
||||||
|
X . . . X X . X . X X X X X X X X . X X X X . . X X .
|
||||||
|
. X X X X . . X . . X X X . X X . . X . . . . X X X .
|
||||||
|
X X . . . X X . . X . X . . . . X X . X . . X . X . X ",
|
||||||
|
"X ",
|
||||||
|
". ",
|
||||||
|
)
|
||||||
|
.expect("String Parse OK");
|
||||||
|
let r = AztecDetectorRXingResult::new(matrix, NO_POINTS.to_vec(), true, 16, 4);
|
||||||
|
decoder::decode(&r);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn testRawBytes() {
|
||||||
|
let bool0 = vec![false; 0];
|
||||||
|
let bool1 = vec![true];
|
||||||
|
let bool7 = vec![true, false, true, false, true, false, true];
|
||||||
|
let bool8 = vec![true, false, true, false, true, false, true, false];
|
||||||
|
let bool9 = vec![true, false, true, false, true, false, true, false, true];
|
||||||
|
let bool16 = vec![
|
||||||
|
false, true, true, false, false, false, true, true, true, true, false, false, false, false,
|
||||||
|
false, true,
|
||||||
|
];
|
||||||
|
let byte0 = vec![0u8; 0];
|
||||||
|
let byte1 = vec![-128i8 as u8];
|
||||||
|
let byte7 = vec![-86i8 as u8];
|
||||||
|
let byte8 = vec![-86i8 as u8];
|
||||||
|
let byte9 = vec![-86i8 as u8, -128i8 as u8];
|
||||||
|
let byte16 = vec![99, -63i8 as u8];
|
||||||
|
|
||||||
|
assert_eq!(byte0, decoder::convertBoolArrayToByteArray(&bool0));
|
||||||
|
assert_eq!(byte1, decoder::convertBoolArrayToByteArray(&bool1));
|
||||||
|
assert_eq!(byte7, decoder::convertBoolArrayToByteArray(&bool7));
|
||||||
|
assert_eq!(byte8, decoder::convertBoolArrayToByteArray(&bool8));
|
||||||
|
assert_eq!(byte9, decoder::convertBoolArrayToByteArray(&bool9));
|
||||||
|
assert_eq!(byte16, decoder::convertBoolArrayToByteArray(&bool16));
|
||||||
|
}
|
||||||
@@ -14,27 +14,29 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.google.zxing.aztec.encoder;
|
// package com.google.zxing.aztec.encoder;
|
||||||
|
|
||||||
import com.google.zxing.BarcodeFormat;
|
// import com.google.zxing.BarcodeFormat;
|
||||||
import com.google.zxing.EncodeHintType;
|
// import com.google.zxing.EncodeHintType;
|
||||||
import com.google.zxing.FormatException;
|
// import com.google.zxing.FormatException;
|
||||||
import com.google.zxing.RXingResultPoint;
|
// import com.google.zxing.RXingResultPoint;
|
||||||
import com.google.zxing.aztec.AztecDetectorRXingResult;
|
// import com.google.zxing.aztec.AztecDetectorRXingResult;
|
||||||
import com.google.zxing.aztec.AztecWriter;
|
// import com.google.zxing.aztec.AztecWriter;
|
||||||
import com.google.zxing.aztec.decoder.Decoder;
|
// import com.google.zxing.aztec.decoder.Decoder;
|
||||||
import com.google.zxing.common.BitArray;
|
// import com.google.zxing.common.BitArray;
|
||||||
import com.google.zxing.common.BitMatrix;
|
// import com.google.zxing.common.BitMatrix;
|
||||||
import com.google.zxing.common.DecoderRXingResult;
|
// import com.google.zxing.common.DecoderRXingResult;
|
||||||
import org.junit.Assert;
|
// import org.junit.Assert;
|
||||||
import org.junit.Test;
|
// import org.junit.Test;
|
||||||
|
|
||||||
import java.nio.charset.Charset;
|
// import java.nio.charset.Charset;
|
||||||
import java.nio.charset.StandardCharsets;
|
// import java.nio.charset.StandardCharsets;
|
||||||
import java.util.EnumMap;
|
// import java.util.EnumMap;
|
||||||
import java.util.Map;
|
// import java.util.Map;
|
||||||
import java.util.Random;
|
// import java.util.Random;
|
||||||
import java.util.regex.Pattern;
|
// import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
use crate::common::BitArray;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Aztec 2D generator unit tests.
|
* Aztec 2D generator unit tests.
|
||||||
@@ -42,22 +44,21 @@ import java.util.regex.Pattern;
|
|||||||
* @author Rustam Abdullaev
|
* @author Rustam Abdullaev
|
||||||
* @author Frank Yellin
|
* @author Frank Yellin
|
||||||
*/
|
*/
|
||||||
public final class EncoderTest extends Assert {
|
|
||||||
|
|
||||||
private static final Charset ISO_8859_1 = StandardCharsets.ISO_8859_1;
|
const ISO_8859_1:&'static encoding::Encoding = StandardCharsets.ISO_8859_1;
|
||||||
private static final Charset UTF_8 = StandardCharsets.UTF_8;
|
const UTF_8 :&'static encoding::Encoding= StandardCharsets.UTF_8;
|
||||||
private static final Charset SHIFT_JIS = Charset.forName("Shift_JIS");
|
const SHIFT_JIS:&'static encoding::Encoding = Charset.forName("Shift_JIS");
|
||||||
private static final Charset ISO_8859_15 = Charset.forName("ISO-8859-15");
|
const ISO_8859_15:&'static encoding::Encoding = Charset.forName("ISO-8859-15");
|
||||||
private static final Charset WINDOWS_1252 = Charset.forName("Windows-1252");
|
const WINDOWS_1252 :&'static encoding::Encoding= Charset.forName("Windows-1252");
|
||||||
|
|
||||||
private static final Pattern DOTX = Pattern.compile("[^.X]");
|
const DOTX : &str = "[^.X]";
|
||||||
private static final Pattern SPACES = Pattern.compile("\\s+");
|
const SPACES :&str= "\\s+";
|
||||||
private static final RXingResultPoint[] NO_POINTS = new RXingResultPoint[0];
|
const NO_POINTS:Vec<RXingResultPoint> = Vec::new();
|
||||||
|
|
||||||
// real life tests
|
// real life tests
|
||||||
|
|
||||||
@Test
|
#[test]
|
||||||
public void testEncode1() {
|
fn testEncode1() {
|
||||||
testEncode("This is an example Aztec symbol for Wikipedia.", true, 3,
|
testEncode("This is an example Aztec symbol for Wikipedia.", true, 3,
|
||||||
"X X X X X X X X \n" +
|
"X X X X X X X X \n" +
|
||||||
"X X X X X X X X X X \n" +
|
"X X X X X X X X X X \n" +
|
||||||
@@ -84,8 +85,8 @@ public final class EncoderTest extends Assert {
|
|||||||
" X X X X X X X X X X \n");
|
" X X X X X X X X X X \n");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
#[test]
|
||||||
public void testEncode2() {
|
fn testEncode2() {
|
||||||
testEncode("Aztec Code is a public domain 2D matrix barcode symbology" +
|
testEncode("Aztec Code is a public domain 2D matrix barcode symbology" +
|
||||||
" of nominally square symbols built on a square grid with a " +
|
" of nominally square symbols built on a square grid with a " +
|
||||||
"distinctive square bullseye pattern at their center.", false, 6,
|
"distinctive square bullseye pattern at their center.", false, 6,
|
||||||
@@ -132,57 +133,57 @@ public final class EncoderTest extends Assert {
|
|||||||
"X X X X X X X X X X X X X \n");
|
"X X X X X X X X X X X X X \n");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testAztecWriter() throws Exception {
|
fn testAztecWriter() {
|
||||||
testWriter("Espa\u00F1ol", null, 25, true, 1); // Without ECI (implicit ISO-8859-1)
|
testWriter("Espa\u{00F1}ol", null, 25, true, 1); // Without ECI (implicit ISO-8859-1)
|
||||||
testWriter("Espa\u00F1ol", ISO_8859_1, 25, true, 1); // Explicit ISO-8859-1
|
testWriter("Espa\u{00F1}ol", ISO_8859_1, 25, true, 1); // Explicit ISO-8859-1
|
||||||
testWriter("\u20AC 1 sample data.", WINDOWS_1252, 25, true, 2); // ISO-8859-1 can't encode Euro; Windows-1252 can
|
testWriter("\u{20AC} 1 sample data.", WINDOWS_1252, 25, true, 2); // ISO-8859-1 can't encode Euro; Windows-1252 can
|
||||||
testWriter("\u20AC 1 sample data.", ISO_8859_15, 25, true, 2);
|
testWriter("\u{20AC} 1 sample data.", ISO_8859_15, 25, true, 2);
|
||||||
testWriter("\u20AC 1 sample data.", UTF_8, 25, true, 2);
|
testWriter("\u{20AC} 1 sample data.", UTF_8, 25, true, 2);
|
||||||
testWriter("\u20AC 1 sample data.", UTF_8, 100, true, 3);
|
testWriter("\u{20AC} 1 sample data.", UTF_8, 100, true, 3);
|
||||||
testWriter("\u20AC 1 sample data.", UTF_8, 300, true, 4);
|
testWriter("\u{20AC} 1 sample data.", UTF_8, 300, true, 4);
|
||||||
testWriter("\u20AC 1 sample data.", UTF_8, 500, false, 5);
|
testWriter("\u{20AC} 1 sample data.", UTF_8, 500, false, 5);
|
||||||
testWriter("The capital of Japan is named \u6771\u4EAC.", SHIFT_JIS, 25, true, 3);
|
testWriter("The capital of Japan is named \u{6771}\u{4EAC}.", SHIFT_JIS, 25, true, 3);
|
||||||
// Test AztecWriter defaults
|
// Test AztecWriter defaults
|
||||||
String data = "In ut magna vel mauris malesuada";
|
let data = "In ut magna vel mauris malesuada";
|
||||||
AztecWriter writer = new AztecWriter();
|
let writer = AztecWriter::new();
|
||||||
BitMatrix matrix = writer.encode(data, BarcodeFormat.AZTEC, 0, 0);
|
let matrix = writer.encode(data, BarcodeFormat.AZTEC, 0, 0);
|
||||||
AztecCode aztec = Encoder.encode(data,
|
let aztec = Encoder.encode(data,
|
||||||
Encoder.DEFAULT_EC_PERCENT, Encoder.DEFAULT_AZTEC_LAYERS);
|
Encoder.DEFAULT_EC_PERCENT, Encoder.DEFAULT_AZTEC_LAYERS);
|
||||||
BitMatrix expectedMatrix = aztec.getMatrix();
|
let expectedMatrix = aztec.getMatrix();
|
||||||
assertEquals(matrix, expectedMatrix);
|
assertEquals(matrix, expectedMatrix);
|
||||||
}
|
}
|
||||||
|
|
||||||
// synthetic tests (encode-decode round-trip)
|
// synthetic tests (encode-decode round-trip)
|
||||||
|
|
||||||
@Test
|
#[test]
|
||||||
public void testEncodeDecode1() throws Exception {
|
fn testEncodeDecode1() {
|
||||||
testEncodeDecode("Abc123!", true, 1);
|
testEncodeDecode("Abc123!", true, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
#[test]
|
||||||
public void testEncodeDecode2() throws Exception {
|
fn testEncodeDecode2() {
|
||||||
testEncodeDecode("Lorem ipsum. http://test/", true, 2);
|
testEncodeDecode("Lorem ipsum. http://test/", true, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
#[test]
|
||||||
public void testEncodeDecode3() throws Exception {
|
fn testEncodeDecode3() {
|
||||||
testEncodeDecode("AAAANAAAANAAAANAAAANAAAANAAAANAAAANAAAANAAAANAAAAN", true, 3);
|
testEncodeDecode("AAAANAAAANAAAANAAAANAAAANAAAANAAAANAAAANAAAANAAAAN", true, 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
#[test]
|
||||||
public void testEncodeDecode4() throws Exception {
|
fn testEncodeDecode4() {
|
||||||
testEncodeDecode("http://test/~!@#*^%&)__ ;:'\"[]{}\\|-+-=`1029384", true, 4);
|
testEncodeDecode("http://test/~!@#*^%&)__ ;:'\"[]{}\\|-+-=`1029384", true, 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
#[test]
|
||||||
public void testEncodeDecode5() throws Exception {
|
fn testEncodeDecode5() {
|
||||||
testEncodeDecode("http://test/~!@#*^%&)__ ;:'\"[]{}\\|-+-=`1029384756<>/?abc"
|
testEncodeDecode("http://test/~!@#*^%&)__ ;:'\"[]{}\\|-+-=`1029384756<>/?abc"
|
||||||
+ "Four score and seven our forefathers brought forth", false, 5);
|
+ "Four score and seven our forefathers brought forth", false, 5);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
#[test]
|
||||||
public void testEncodeDecode10() throws Exception {
|
fn testEncodeDecode10() {
|
||||||
testEncodeDecode("In ut magna vel mauris malesuada dictum. Nulla ullamcorper metus quis diam" +
|
testEncodeDecode("In ut magna vel mauris malesuada dictum. Nulla ullamcorper metus quis diam" +
|
||||||
" cursus facilisis. Sed mollis quam id justo rutrum sagittis. Donec laoreet rutrum" +
|
" cursus facilisis. Sed mollis quam id justo rutrum sagittis. Donec laoreet rutrum" +
|
||||||
" est, nec convallis mauris condimentum sit amet. Phasellus gravida, justo et congue" +
|
" est, nec convallis mauris condimentum sit amet. Phasellus gravida, justo et congue" +
|
||||||
@@ -191,8 +192,8 @@ public final class EncoderTest extends Assert {
|
|||||||
" elementum sapien dolor et diam.", false, 10);
|
" elementum sapien dolor et diam.", false, 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
#[test]
|
||||||
public void testEncodeDecode23() throws Exception {
|
fn testEncodeDecode23() {
|
||||||
testEncodeDecode("In ut magna vel mauris malesuada dictum. Nulla ullamcorper metus quis diam" +
|
testEncodeDecode("In ut magna vel mauris malesuada dictum. Nulla ullamcorper metus quis diam" +
|
||||||
" cursus facilisis. Sed mollis quam id justo rutrum sagittis. Donec laoreet rutrum" +
|
" cursus facilisis. Sed mollis quam id justo rutrum sagittis. Donec laoreet rutrum" +
|
||||||
" est, nec convallis mauris condimentum sit amet. Phasellus gravida, justo et congue" +
|
" est, nec convallis mauris condimentum sit amet. Phasellus gravida, justo et congue" +
|
||||||
@@ -217,8 +218,8 @@ public final class EncoderTest extends Assert {
|
|||||||
" erat pulvinar nisi, id elementum sapien dolor et diam.", false, 23);
|
" erat pulvinar nisi, id elementum sapien dolor et diam.", false, 23);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
#[test]
|
||||||
public void testEncodeDecode31() throws Exception {
|
fn testEncodeDecode31() {
|
||||||
testEncodeDecode("In ut magna vel mauris malesuada dictum. Nulla ullamcorper metus quis diam" +
|
testEncodeDecode("In ut magna vel mauris malesuada dictum. Nulla ullamcorper metus quis diam" +
|
||||||
" cursus facilisis. Sed mollis quam id justo rutrum sagittis. Donec laoreet rutrum" +
|
" cursus facilisis. Sed mollis quam id justo rutrum sagittis. Donec laoreet rutrum" +
|
||||||
" est, nec convallis mauris condimentum sit amet. Phasellus gravida, justo et congue" +
|
" est, nec convallis mauris condimentum sit amet. Phasellus gravida, justo et congue" +
|
||||||
@@ -258,16 +259,16 @@ public final class EncoderTest extends Assert {
|
|||||||
" hendrerit felis turpis nec lorem.", false, 31);
|
" hendrerit felis turpis nec lorem.", false, 31);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
#[test]
|
||||||
public void testGenerateModeMessage() {
|
fn testGenerateModeMessage() {
|
||||||
testModeMessage(true, 2, 29, ".X .XXX.. ...X XX.. ..X .XX. .XX.X");
|
testModeMessage(true, 2, 29, ".X .XXX.. ...X XX.. ..X .XX. .XX.X");
|
||||||
testModeMessage(true, 4, 64, "XX XXXXXX .X.. ...X ..XX .X.. XX..");
|
testModeMessage(true, 4, 64, "XX XXXXXX .X.. ...X ..XX .X.. XX..");
|
||||||
testModeMessage(false, 21, 660, "X.X.. .X.X..X..XX .XXX ..X.. .XXX. .X... ..XXX");
|
testModeMessage(false, 21, 660, "X.X.. .X.X..X..XX .XXX ..X.. .XXX. .X... ..XXX");
|
||||||
testModeMessage(false, 32, 4096, "XXXXX XXXXXXXXXXX X.X. ..... XXX.X ..X.. X.XXX");
|
testModeMessage(false, 32, 4096, "XXXXX XXXXXXXXXXX X.X. ..... XXX.X ..X.. X.XXX");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
#[test]
|
||||||
public void testStuffBits() {
|
fn testStuffBits() {
|
||||||
testStuffBits(5, ".X.X. X.X.X .X.X.",
|
testStuffBits(5, ".X.X. X.X.X .X.X.",
|
||||||
".X.X. X.X.X .X.X.");
|
".X.X. X.X.X .X.X.");
|
||||||
testStuffBits(5, ".X.X. ..... .X.X",
|
testStuffBits(5, ".X.X. ..... .X.X",
|
||||||
@@ -285,8 +286,8 @@ public final class EncoderTest extends Assert {
|
|||||||
".....X ...XXX XX..XX ..X... ..X.X. X..... X.X... ....X. X..... X....X X..X.. .....X X.X..X XXX.XX .XXXXX");
|
".....X ...XXX XX..XX ..X... ..X.X. X..... X.X... ....X. X..... X....X X..X.. .....X X.X..X XXX.XX .XXXXX");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
#[test]
|
||||||
public void testHighLevelEncode() throws FormatException {
|
fn testHighLevelEncode() {
|
||||||
testHighLevelEncodeString("A. b.",
|
testHighLevelEncodeString("A. b.",
|
||||||
// 'A' P/S '. ' L/L b D/L '.'
|
// 'A' P/S '. ' L/L b D/L '.'
|
||||||
"...X. ..... ...XX XXX.. ...XX XXXX. XX.X");
|
"...X. ..... ...XX XXX.. ...XX XXXX. XX.X");
|
||||||
@@ -315,8 +316,8 @@ public final class EncoderTest extends Assert {
|
|||||||
823);
|
823);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
#[test]
|
||||||
public void testHighLevelEncodeBinary() throws FormatException {
|
fn testHighLevelEncodeBinary() {
|
||||||
// binary short form single byte
|
// binary short form single byte
|
||||||
testHighLevelEncodeString("N\0N",
|
testHighLevelEncodeString("N\0N",
|
||||||
// 'N' B/S =1 '\0' N
|
// 'N' B/S =1 '\0' N
|
||||||
@@ -327,12 +328,12 @@ public final class EncoderTest extends Assert {
|
|||||||
".XXXX XXXXX ...X. ........ .XX.XXX."); // Encode "n" in BINARY
|
".XXXX XXXXX ...X. ........ .XX.XXX."); // Encode "n" in BINARY
|
||||||
|
|
||||||
// binary short form consecutive bytes
|
// binary short form consecutive bytes
|
||||||
testHighLevelEncodeString("N\0\u0080 A",
|
testHighLevelEncodeString("N\0\u{0080} A",
|
||||||
// 'N' B/S =2 '\0' \u0080 ' ' 'A'
|
// 'N' B/S =2 '\0' \u0080 ' ' 'A'
|
||||||
".XXXX XXXXX ...X. ........ X....... ....X ...X.");
|
".XXXX XXXXX ...X. ........ X....... ....X ...X.");
|
||||||
|
|
||||||
// binary skipping over single character
|
// binary skipping over single character
|
||||||
testHighLevelEncodeString("\0a\u00FF\u0080 A",
|
testHighLevelEncodeString("\0a\u{00FF}\u{0080} A",
|
||||||
// B/S =4 '\0' 'a' '\3ff' '\200' ' ' 'A'
|
// B/S =4 '\0' 'a' '\3ff' '\200' ' ' 'A'
|
||||||
"XXXXX ..X.. ........ .XX....X XXXXXXXX X....... ....X ...X.");
|
"XXXXX ..X.. ........ .XX....X XXXXXXXX X....... ....X ...X.");
|
||||||
|
|
||||||
@@ -343,7 +344,7 @@ public final class EncoderTest extends Assert {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Create a string in which every character requires binary
|
// Create a string in which every character requires binary
|
||||||
StringBuilder sb = new StringBuilder();
|
let sb = String::new();
|
||||||
for (int i = 0; i <= 3000; i++) {
|
for (int i = 0; i <= 3000; i++) {
|
||||||
sb.append((char) (128 + (i % 30)));
|
sb.append((char) (128 + (i % 30)));
|
||||||
}
|
}
|
||||||
@@ -402,8 +403,8 @@ public final class EncoderTest extends Assert {
|
|||||||
testHighLevelEncodeString(sb.toString(), 21 + 64 * 8);
|
testHighLevelEncodeString(sb.toString(), 21 + 64 * 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
#[test]
|
||||||
public void testHighLevelEncodePairs() throws FormatException {
|
fn testHighLevelEncodePairs() {
|
||||||
// Typical usage
|
// Typical usage
|
||||||
testHighLevelEncodeString("ABC. DEF\r\n",
|
testHighLevelEncodeString("ABC. DEF\r\n",
|
||||||
// A B C P/S .<sp> D E F P/S \r\n
|
// A B C P/S .<sp> D E F P/S \r\n
|
||||||
@@ -424,17 +425,19 @@ public final class EncoderTest extends Assert {
|
|||||||
"...X. XXXXX ..X.. X....... ..X.XXX. ..X..... X.......");
|
"...X. XXXXX ..X.. X....... ..X.XXX. ..X..... X.......");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = IllegalArgumentException.class)
|
#[test]
|
||||||
public void testUserSpecifiedLayers() {
|
#[should_panic]
|
||||||
|
fn testUserSpecifiedLayers() {
|
||||||
doTestUserSpecifiedLayers(33);
|
doTestUserSpecifiedLayers(33);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = IllegalArgumentException.class)
|
#[test]
|
||||||
public void testUserSpecifiedLayers2() {
|
#[should_panic]
|
||||||
|
fn testUserSpecifiedLayers2() {
|
||||||
doTestUserSpecifiedLayers(-1);
|
doTestUserSpecifiedLayers(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void doTestUserSpecifiedLayers(int userSpecifiedLayers) {
|
fn doTestUserSpecifiedLayers( userSpecifiedLayers:usize) {
|
||||||
String alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
String alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||||
AztecCode aztec = Encoder.encode(alphabet, 25, -2);
|
AztecCode aztec = Encoder.encode(alphabet, 25, -2);
|
||||||
assertEquals(2, aztec.getLayers());
|
assertEquals(2, aztec.getLayers());
|
||||||
@@ -447,8 +450,9 @@ public final class EncoderTest extends Assert {
|
|||||||
Encoder.encode(alphabet, 25, userSpecifiedLayers);
|
Encoder.encode(alphabet, 25, userSpecifiedLayers);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = IllegalArgumentException.class)
|
#[test]
|
||||||
public void testBorderCompact4CaseFailed() {
|
#[should_panic]
|
||||||
|
fn testBorderCompact4CaseFailed() {
|
||||||
// Compact(4) con hold 608 bits of information, but at most 504 can be data. Rest must
|
// Compact(4) con hold 608 bits of information, but at most 504 can be data. Rest must
|
||||||
// be error correction
|
// be error correction
|
||||||
String alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
String alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||||
@@ -457,8 +461,8 @@ public final class EncoderTest extends Assert {
|
|||||||
Encoder.encode(alphabet4, 0, -4);
|
Encoder.encode(alphabet4, 0, -4);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
#[test]
|
||||||
public void testBorderCompact4Case() {
|
fn testBorderCompact4Case() {
|
||||||
// Compact(4) con hold 608 bits of information, but at most 504 can be data. Rest must
|
// Compact(4) con hold 608 bits of information, but at most 504 can be data. Rest must
|
||||||
// be error correction
|
// be error correction
|
||||||
String alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
String alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||||
@@ -479,7 +483,7 @@ public final class EncoderTest extends Assert {
|
|||||||
|
|
||||||
// Helper routines
|
// Helper routines
|
||||||
|
|
||||||
private static void testEncode(String data, boolean compact, int layers, String expected) {
|
fn testEncode( data:&str, compact:bool, layers:usize, expected:&str) {
|
||||||
AztecCode aztec = Encoder.encode(data, 33, Encoder.DEFAULT_AZTEC_LAYERS);
|
AztecCode aztec = Encoder.encode(data, 33, Encoder.DEFAULT_AZTEC_LAYERS);
|
||||||
assertEquals("Unexpected symbol format (compact)", compact, aztec.isCompact());
|
assertEquals("Unexpected symbol format (compact)", compact, aztec.isCompact());
|
||||||
assertEquals("Unexpected nr. of layers", layers, aztec.getLayers());
|
assertEquals("Unexpected nr. of layers", layers, aztec.getLayers());
|
||||||
@@ -487,7 +491,7 @@ public final class EncoderTest extends Assert {
|
|||||||
assertEquals("encode() failed", expected, matrix.toString());
|
assertEquals("encode() failed", expected, matrix.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void testEncodeDecode(String data, boolean compact, int layers) throws Exception {
|
fn testEncodeDecode( data:&str, compact:bool, layers:usize) {
|
||||||
AztecCode aztec = Encoder.encode(data, 25, Encoder.DEFAULT_AZTEC_LAYERS);
|
AztecCode aztec = Encoder.encode(data, 25, Encoder.DEFAULT_AZTEC_LAYERS);
|
||||||
assertEquals("Unexpected symbol format (compact)", compact, aztec.isCompact());
|
assertEquals("Unexpected symbol format (compact)", compact, aztec.isCompact());
|
||||||
assertEquals("Unexpected nr. of layers", layers, aztec.getLayers());
|
assertEquals("Unexpected nr. of layers", layers, aztec.getLayers());
|
||||||
@@ -507,11 +511,11 @@ public final class EncoderTest extends Assert {
|
|||||||
assertEquals(data, res.getText());
|
assertEquals(data, res.getText());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void testWriter(String data,
|
fn testWriter( data:&str,
|
||||||
Charset charset,
|
charset:&'static dyn encoding::Encoding,
|
||||||
int eccPercent,
|
eccPercent:u32,
|
||||||
boolean compact,
|
compact:bool,
|
||||||
int layers) throws FormatException {
|
layers:usize) throws FormatException {
|
||||||
// Perform an encode-decode round-trip because it can be lossy.
|
// Perform an encode-decode round-trip because it can be lossy.
|
||||||
Map<EncodeHintType,Object> hints = new EnumMap<>(EncodeHintType.class);
|
Map<EncodeHintType,Object> hints = new EnumMap<>(EncodeHintType.class);
|
||||||
if (null != charset) {
|
if (null != charset) {
|
||||||
@@ -548,56 +552,35 @@ public final class EncoderTest extends Assert {
|
|||||||
assertEquals(data, res.getText());
|
assertEquals(data, res.getText());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Random getPseudoRandom() {
|
fn getPseudoRandom() -> rand::Rng{
|
||||||
return new Random(0xDEADBEEF);
|
return new Random(0xDEADBEEF);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void testModeMessage(boolean compact, int layers, int words, String expected) {
|
fn testModeMessage( compact:bool, layers:usize, words:usize, expected:&str) {
|
||||||
BitArray in = Encoder.generateModeMessage(compact, layers, words);
|
BitArray in = Encoder.generateModeMessage(compact, layers, words);
|
||||||
assertEquals("generateModeMessage() failed", stripSpace(expected), stripSpace(in.toString()));
|
assertEquals("generateModeMessage() failed", stripSpace(expected), stripSpace(in.toString()));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void testStuffBits(int wordSize, String bits, String expected) {
|
fn testStuffBits( wordSize:usize, bits:&str, expected:&str) {
|
||||||
BitArray in = toBitArray(bits);
|
BitArray in = toBitArray(bits);
|
||||||
BitArray stuffed = Encoder.stuffBits(in, wordSize);
|
BitArray stuffed = Encoder.stuffBits(in, wordSize);
|
||||||
assertEquals("stuffBits() failed for input string: " + bits,
|
assertEquals("stuffBits() failed for input string: " + bits,
|
||||||
stripSpace(expected), stripSpace(stuffed.toString()));
|
stripSpace(expected), stripSpace(stuffed.toString()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static BitArray toBitArray(CharSequence bits) {
|
|
||||||
BitArray in = new BitArray();
|
|
||||||
char[] str = DOTX.matcher(bits).replaceAll("").toCharArray();
|
|
||||||
for (char aStr : str) {
|
|
||||||
in.appendBit(aStr == 'X');
|
|
||||||
}
|
|
||||||
return in;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean[] toBooleanArray(BitArray bitArray) {
|
|
||||||
boolean[] result = new boolean[bitArray.getSize()];
|
|
||||||
for (int i = 0; i < result.length; i++) {
|
|
||||||
result[i] = bitArray.get(i);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void testHighLevelEncodeString(String s, String expectedBits) throws FormatException {
|
fn testHighLevelEncodeString( s:&str, expectedBits:&str) {
|
||||||
BitArray bits = new HighLevelEncoder(s.getBytes(StandardCharsets.ISO_8859_1)).encode();
|
BitArray bits = new HighLevelEncoder(s.getBytes(StandardCharsets.ISO_8859_1)).encode();
|
||||||
String receivedBits = stripSpace(bits.toString());
|
String receivedBits = stripSpace(bits.toString());
|
||||||
assertEquals("highLevelEncode() failed for input string: " + s, stripSpace(expectedBits), receivedBits);
|
assertEquals("highLevelEncode() failed for input string: " + s, stripSpace(expectedBits), receivedBits);
|
||||||
assertEquals(s, Decoder.highLevelDecode(toBooleanArray(bits)));
|
assertEquals(s, Decoder.highLevelDecode(toBooleanArray(bits)));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void testHighLevelEncodeString(String s, int expectedReceivedBits) throws FormatException {
|
fn testHighLevelEncodeString( s:&str, expectedReceivedBits:u32) {
|
||||||
BitArray bits = new HighLevelEncoder(s.getBytes(StandardCharsets.ISO_8859_1)).encode();
|
BitArray bits = new HighLevelEncoder(s.getBytes(StandardCharsets.ISO_8859_1)).encode();
|
||||||
int receivedBitCount = stripSpace(bits.toString()).length();
|
int receivedBitCount = stripSpace(bits.toString()).length();
|
||||||
assertEquals("highLevelEncode() failed for input string: " + s,
|
assertEquals("highLevelEncode() failed for input string: " + s,
|
||||||
expectedReceivedBits, receivedBitCount);
|
expectedReceivedBits, receivedBitCount);
|
||||||
assertEquals(s, Decoder.highLevelDecode(toBooleanArray(bits)));
|
assertEquals(s, Decoder.highLevelDecode(toBooleanArray(bits)));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String stripSpace(String s) {
|
|
||||||
return SPACES.matcher(s).replaceAll("");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
572
src/aztec/decoder.rs
Normal file
572
src/aztec/decoder.rs
Normal file
@@ -0,0 +1,572 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010 ZXing authors
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// package com.google.zxing.aztec.decoder;
|
||||||
|
|
||||||
|
// import com.google.zxing.FormatException;
|
||||||
|
// import com.google.zxing.aztec.AztecDetectorRXingResult;
|
||||||
|
// import com.google.zxing.common.BitMatrix;
|
||||||
|
// import com.google.zxing.common.CharacterSetECI;
|
||||||
|
// import com.google.zxing.common.DecoderRXingResult;
|
||||||
|
// import com.google.zxing.common.reedsolomon.GenericGF;
|
||||||
|
// import com.google.zxing.common.reedsolomon.ReedSolomonDecoder;
|
||||||
|
// import com.google.zxing.common.reedsolomon.ReedSolomonException;
|
||||||
|
|
||||||
|
// import java.io.ByteArrayOutputStream;
|
||||||
|
// import java.io.UnsupportedEncodingException;
|
||||||
|
// import java.nio.charset.Charset;
|
||||||
|
// import java.nio.charset.StandardCharsets;
|
||||||
|
// import java.util.Arrays;
|
||||||
|
|
||||||
|
use encoding::Encoding;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
common::{
|
||||||
|
self,
|
||||||
|
reedsolomon::{
|
||||||
|
get_predefined_genericgf, GenericGF, PredefinedGenericGF, ReedSolomonDecoder,
|
||||||
|
},
|
||||||
|
BitMatrix, CharacterSetECI, DecoderRXingResult, DetectorRXingResult,
|
||||||
|
},
|
||||||
|
exceptions::Exceptions,
|
||||||
|
};
|
||||||
|
|
||||||
|
use super::AztecDetectorResult::AztecDetectorRXingResult;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>The main class which implements Aztec Code decoding -- as opposed to locating and extracting
|
||||||
|
* the Aztec Code from an image.</p>
|
||||||
|
*
|
||||||
|
* @author David Olivier
|
||||||
|
*/
|
||||||
|
|
||||||
|
#[derive(PartialEq, Eq,Copy,Clone)]
|
||||||
|
enum Table {
|
||||||
|
UPPER,
|
||||||
|
LOWER,
|
||||||
|
MIXED,
|
||||||
|
DIGIT,
|
||||||
|
PUNCT,
|
||||||
|
BINARY,
|
||||||
|
}
|
||||||
|
|
||||||
|
const UPPER_TABLE: [&str; 32] = [
|
||||||
|
"CTRL_PS", " ", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P",
|
||||||
|
"Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "CTRL_LL", "CTRL_ML", "CTRL_DL", "CTRL_BS",
|
||||||
|
];
|
||||||
|
|
||||||
|
const LOWER_TABLE: [&str; 32] = [
|
||||||
|
"CTRL_PS", " ", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p",
|
||||||
|
"q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "CTRL_US", "CTRL_ML", "CTRL_DL", "CTRL_BS",
|
||||||
|
];
|
||||||
|
|
||||||
|
const MIXED_TABLE: [&str; 32] = [
|
||||||
|
"CTRL_PS", " ", "\u{1}", "\u{2}", "\u{3}", "\u{4}", "\u{5}", "\u{6}", "\u{7}", "\u{8}", "\t",
|
||||||
|
"\n", "\u{13}", "\u{0c}", "\r", "\u{33}", "\u{34}", "\u{35}", "\u{36}", "\u{37}", "@", "\\",
|
||||||
|
"^", "_", "`", "|", "~", "\u{177}", "CTRL_LL", "CTRL_UL", "CTRL_PL", "CTRL_BS",
|
||||||
|
];
|
||||||
|
|
||||||
|
const PUNCT_TABLE: [&str; 32] = [
|
||||||
|
"FLG(n)", "\r", "\r\n", ". ", ", ", ": ", "!", "\"", "#", "$", "%", "&", "'", "(", ")", "*",
|
||||||
|
"+", ",", "-", ".", "/", ":", ";", "<", "=", ">", "?", "[", "]", "{", "}", "CTRL_UL",
|
||||||
|
];
|
||||||
|
|
||||||
|
const DIGIT_TABLE: [&str; 16] = [
|
||||||
|
"CTRL_PS", " ", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", ",", ".", "CTRL_UL",
|
||||||
|
"CTRL_US",
|
||||||
|
];
|
||||||
|
|
||||||
|
// private static final Charset DEFAULT_ENCODING = StandardCharsets.ISO_8859_1;
|
||||||
|
|
||||||
|
// private AztecDetectorRXingResult ddata;
|
||||||
|
|
||||||
|
pub fn decode(
|
||||||
|
detectorRXingResult: &AztecDetectorRXingResult,
|
||||||
|
) -> Result<DecoderRXingResult, Exceptions> {
|
||||||
|
//let mut detectorRXingResult = detectorRXingResult.clone();
|
||||||
|
let matrix = detectorRXingResult.getBits();
|
||||||
|
let rawbits = extractBits(&detectorRXingResult, matrix);
|
||||||
|
let correctedBits = correctBits(&detectorRXingResult, &rawbits)?;
|
||||||
|
let rawBytes = convertBoolArrayToByteArray(&correctedBits.correctBits);
|
||||||
|
let result = getEncodedData(&correctedBits.correctBits);
|
||||||
|
let mut decoderRXingResult = DecoderRXingResult::new(
|
||||||
|
rawBytes,
|
||||||
|
result?,
|
||||||
|
Vec::new(),
|
||||||
|
format!("{}%", correctedBits.ecLevel),
|
||||||
|
);
|
||||||
|
decoderRXingResult.setNumBits(correctedBits.correctBits.len());
|
||||||
|
|
||||||
|
Ok(decoderRXingResult)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This method is used for testing the high-level encoder
|
||||||
|
pub fn highLevelDecode(correctedBits: &[bool]) -> Result<String, Exceptions> {
|
||||||
|
getEncodedData(correctedBits)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the string encoded in the aztec code bits
|
||||||
|
*
|
||||||
|
* @return the decoded string
|
||||||
|
*/
|
||||||
|
fn getEncodedData(correctedBits: &[bool]) -> Result<String, Exceptions> {
|
||||||
|
let endIndex = correctedBits.len();
|
||||||
|
let mut latchTable = Table::UPPER; // table most recently latched to
|
||||||
|
let mut shiftTable = Table::UPPER; // table to use for the next read
|
||||||
|
|
||||||
|
// Final decoded string result
|
||||||
|
// (correctedBits-5) / 4 is an upper bound on the size (all-digit result)
|
||||||
|
let mut result = String::with_capacity((correctedBits.len() - 5) / 4);
|
||||||
|
|
||||||
|
// Intermediary buffer of decoded bytes, which is decoded into a string and flushed
|
||||||
|
// when character encoding changes (ECI) or input ends.
|
||||||
|
let mut decodedBytes: Vec<u8> = Vec::new();
|
||||||
|
let mut encdr: &'static dyn encoding::Encoding = encoding::all::UTF_8;
|
||||||
|
|
||||||
|
let mut index = 0;
|
||||||
|
while index < endIndex {
|
||||||
|
if shiftTable == Table::BINARY {
|
||||||
|
if endIndex - index < 5 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
let mut length = readCode(correctedBits, index, 5);
|
||||||
|
index += 5;
|
||||||
|
if length == 0 {
|
||||||
|
if endIndex - index < 11 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
length = readCode(correctedBits, index, 11) + 31;
|
||||||
|
index += 11;
|
||||||
|
}
|
||||||
|
for _charCount in 0..length {
|
||||||
|
// for (int charCount = 0; charCount < length; charCount++) {
|
||||||
|
if endIndex - index < 8 {
|
||||||
|
index = endIndex; // Force outer loop to exit
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
let code = readCode(correctedBits, index, 8);
|
||||||
|
decodedBytes.push(code as u8);
|
||||||
|
index += 8;
|
||||||
|
}
|
||||||
|
// Go back to whatever mode we had been in
|
||||||
|
shiftTable = latchTable;
|
||||||
|
} else {
|
||||||
|
let size = if shiftTable == Table::DIGIT { 4 } else { 5 };
|
||||||
|
if endIndex - index < size {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
let code = readCode(correctedBits, index, size);
|
||||||
|
index += size;
|
||||||
|
let str = getCharacter(shiftTable, code)?;
|
||||||
|
if "FLG(n)" == str {
|
||||||
|
if endIndex - index < 3 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
let mut n = readCode(correctedBits, index, 3);
|
||||||
|
index += 3;
|
||||||
|
// flush bytes, FLG changes state
|
||||||
|
// try {
|
||||||
|
result.push_str(&String::from_utf8(decodedBytes.clone()).unwrap());
|
||||||
|
// result.append(decodedBytes.toString(encoding.name()));
|
||||||
|
// } catch (UnsupportedEncodingException uee) {
|
||||||
|
// throw new IllegalStateException(uee);
|
||||||
|
// }
|
||||||
|
decodedBytes.clear();
|
||||||
|
match n {
|
||||||
|
0 => result.push(29 as char), // translate FNC1 as ASCII 29
|
||||||
|
7 => {
|
||||||
|
return Err(Exceptions::FormatException(
|
||||||
|
"FLG(7) is reserved and illegal".to_owned(),
|
||||||
|
))
|
||||||
|
} // FLG(7) is reserved and illegal
|
||||||
|
_ => {
|
||||||
|
// ECI is decimal integer encoded as 1-6 codes in DIGIT mode
|
||||||
|
let mut eci = 0;
|
||||||
|
if endIndex - index < 4 * (n as usize) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
while n > 0 {
|
||||||
|
//while (n-- > 0) {
|
||||||
|
let nextDigit = readCode(correctedBits, index, 4);
|
||||||
|
index += 4;
|
||||||
|
if nextDigit < 2 || nextDigit > 11 {
|
||||||
|
return Err(Exceptions::FormatException(
|
||||||
|
"Not a decimal digit".to_owned(),
|
||||||
|
)); // Not a decimal digit
|
||||||
|
}
|
||||||
|
eci = eci * 10 + (nextDigit - 2);
|
||||||
|
n -= 1;
|
||||||
|
}
|
||||||
|
let charsetECI = CharacterSetECI::getCharacterSetECIByValue(eci);
|
||||||
|
if charsetECI.is_err() {
|
||||||
|
return Err(Exceptions::FormatException(
|
||||||
|
"Charset must exist".to_owned(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
encdr = CharacterSetECI::getCharset(&charsetECI?);
|
||||||
|
// encdr = charsetECI?::getCharset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// switch (n) {
|
||||||
|
// case 0:
|
||||||
|
// result.append(29 as char); // translate FNC1 as ASCII 29
|
||||||
|
// break;
|
||||||
|
// case 7:
|
||||||
|
// throw FormatException.getFormatInstance(); // FLG(7) is reserved and illegal
|
||||||
|
// default:
|
||||||
|
// // ECI is decimal integer encoded as 1-6 codes in DIGIT mode
|
||||||
|
// int eci = 0;
|
||||||
|
// if (endIndex - index < 4 * n) {
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
// while (n-- > 0) {
|
||||||
|
// int nextDigit = readCode(correctedBits, index, 4);
|
||||||
|
// index += 4;
|
||||||
|
// if (nextDigit < 2 || nextDigit > 11) {
|
||||||
|
// throw FormatException.getFormatInstance(); // Not a decimal digit
|
||||||
|
// }
|
||||||
|
// eci = eci * 10 + (nextDigit - 2);
|
||||||
|
// }
|
||||||
|
// CharacterSetECI charsetECI = CharacterSetECI.getCharacterSetECIByValue(eci);
|
||||||
|
// if (charsetECI == null) {
|
||||||
|
// throw FormatException.getFormatInstance();
|
||||||
|
// }
|
||||||
|
// encoding = charsetECI.getCharset();
|
||||||
|
// }
|
||||||
|
// Go back to whatever mode we had been in
|
||||||
|
shiftTable = latchTable;
|
||||||
|
} else if str.starts_with("CTRL_") {
|
||||||
|
// Table changes
|
||||||
|
// ISO/IEC 24778:2008 prescribes ending a shift sequence in the mode from which it was invoked.
|
||||||
|
// That's including when that mode is a shift.
|
||||||
|
// Our test case dlusbs.png for issue #642 exercises that.
|
||||||
|
latchTable = shiftTable; // Latch the current mode, so as to return to Upper after U/S B/S
|
||||||
|
shiftTable = getTable(str.chars().nth(5).unwrap());
|
||||||
|
if str.chars().nth(6).unwrap() == 'L' {
|
||||||
|
latchTable = shiftTable;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Though stored as a table of strings for convenience, codes actually represent 1 or 2 *bytes*.
|
||||||
|
let b = str.as_bytes();
|
||||||
|
//let b = str.getBytes(StandardCharsets.US_ASCII);
|
||||||
|
//decodedBytes.write(b, 0, b.length);
|
||||||
|
for bt in b {
|
||||||
|
decodedBytes.push(*bt);
|
||||||
|
}
|
||||||
|
// Go back to whatever mode we had been in
|
||||||
|
shiftTable = latchTable;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//try {
|
||||||
|
if let Ok(str) = encdr.decode(&decodedBytes, encoding::DecoderTrap::Strict) {
|
||||||
|
result.push_str(&str);
|
||||||
|
} else {
|
||||||
|
return Err(Exceptions::IllegalStateException("bad encoding".to_owned()));
|
||||||
|
}
|
||||||
|
// result.push_str(decodedBytes.toString(encoding.name()));
|
||||||
|
//} catch (UnsupportedEncodingException uee) {
|
||||||
|
// can't happen
|
||||||
|
//throw new IllegalStateException(uee);
|
||||||
|
//}
|
||||||
|
Ok(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gets the table corresponding to the char passed
|
||||||
|
*/
|
||||||
|
fn getTable(t: char) -> Table {
|
||||||
|
match t {
|
||||||
|
'L' => Table::LOWER,
|
||||||
|
'P' => Table::PUNCT,
|
||||||
|
'M' => Table::MIXED,
|
||||||
|
'D' => Table::DIGIT,
|
||||||
|
'B' => Table::BINARY,
|
||||||
|
_ => Table::UPPER,
|
||||||
|
}
|
||||||
|
// switch (t) {
|
||||||
|
// case 'L':
|
||||||
|
// return Table.LOWER;
|
||||||
|
// case 'P':
|
||||||
|
// return Table.PUNCT;
|
||||||
|
// case 'M':
|
||||||
|
// return Table.MIXED;
|
||||||
|
// case 'D':
|
||||||
|
// return Table.DIGIT;
|
||||||
|
// case 'B':
|
||||||
|
// return Table.BINARY;
|
||||||
|
// case 'U':
|
||||||
|
// default:
|
||||||
|
// return Table.UPPER;
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the character (or string) corresponding to the passed code in the given table
|
||||||
|
*
|
||||||
|
* @param table the table used
|
||||||
|
* @param code the code of the character
|
||||||
|
*/
|
||||||
|
fn getCharacter(table: Table, code: u32) -> Result<&'static str, Exceptions> {
|
||||||
|
match table {
|
||||||
|
Table::UPPER => Ok(UPPER_TABLE[code as usize]),
|
||||||
|
Table::LOWER => Ok(LOWER_TABLE[code as usize]),
|
||||||
|
Table::MIXED => Ok(MIXED_TABLE[code as usize]),
|
||||||
|
Table::DIGIT => Ok(DIGIT_TABLE[code as usize]),
|
||||||
|
Table::PUNCT => Ok(PUNCT_TABLE[code as usize]),
|
||||||
|
_ => Err(Exceptions::IllegalStateException("Bad table".to_owned())),
|
||||||
|
}
|
||||||
|
// switch (table) {
|
||||||
|
// case UPPER:
|
||||||
|
// return UPPER_TABLE[code];
|
||||||
|
// case LOWER:
|
||||||
|
// return LOWER_TABLE[code];
|
||||||
|
// case MIXED:
|
||||||
|
// return MIXED_TABLE[code];
|
||||||
|
// case PUNCT:
|
||||||
|
// return PUNCT_TABLE[code];
|
||||||
|
// case DIGIT:
|
||||||
|
// return DIGIT_TABLE[code];
|
||||||
|
// default:
|
||||||
|
// // Should not reach here.
|
||||||
|
// throw new IllegalStateException("Bad table");
|
||||||
|
}
|
||||||
|
|
||||||
|
struct CorrectedBitsRXingResult {
|
||||||
|
correctBits: Vec<bool>,
|
||||||
|
ecLevel: u32,
|
||||||
|
}
|
||||||
|
impl CorrectedBitsRXingResult {
|
||||||
|
pub fn new(correctBits: Vec<bool>, ecLevel: u32) -> Self {
|
||||||
|
Self {
|
||||||
|
correctBits,
|
||||||
|
ecLevel,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Performs RS error correction on an array of bits.</p>
|
||||||
|
*
|
||||||
|
* @return the corrected array
|
||||||
|
* @throws FormatException if the input contains too many errors
|
||||||
|
*/
|
||||||
|
fn correctBits(
|
||||||
|
ddata: &&AztecDetectorRXingResult,
|
||||||
|
rawbits: &[bool],
|
||||||
|
) -> Result<CorrectedBitsRXingResult, Exceptions> {
|
||||||
|
let gf: GenericGF;
|
||||||
|
let codewordSize;
|
||||||
|
|
||||||
|
if ddata.getNbLayers() <= 2 {
|
||||||
|
codewordSize = 6;
|
||||||
|
gf = get_predefined_genericgf(PredefinedGenericGF::AztecData6); //GenericGF.AZTEC_DATA_6;
|
||||||
|
} else if ddata.getNbLayers() <= 8 {
|
||||||
|
codewordSize = 8;
|
||||||
|
gf = get_predefined_genericgf(PredefinedGenericGF::AztecData8); //GenericGF.AZTEC_DATA_8;
|
||||||
|
} else if ddata.getNbLayers() <= 22 {
|
||||||
|
codewordSize = 10;
|
||||||
|
gf = get_predefined_genericgf(PredefinedGenericGF::AztecData10); //GenericGF.AZTEC_DATA_10;
|
||||||
|
} else {
|
||||||
|
codewordSize = 12;
|
||||||
|
gf = get_predefined_genericgf(PredefinedGenericGF::AztecData12); //GenericGF.AZTEC_DATA_12;
|
||||||
|
}
|
||||||
|
|
||||||
|
let numDataCodewords = ddata.getNbDatablocks();
|
||||||
|
let numCodewords = rawbits.len() / codewordSize;
|
||||||
|
if numCodewords < numDataCodewords as usize {
|
||||||
|
return Err(Exceptions::FormatException(format!(
|
||||||
|
"numCodewords {}< numDataCodewords{}",
|
||||||
|
numCodewords, numDataCodewords
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
let mut offset = rawbits.len() % codewordSize;
|
||||||
|
|
||||||
|
let mut dataWords = vec![0i32; numCodewords];
|
||||||
|
for i in 0..numCodewords {
|
||||||
|
// for (int i = 0; i < numCodewords; i++, offset += codewordSize) {
|
||||||
|
dataWords[i] = readCode(rawbits, offset, codewordSize) as i32;
|
||||||
|
offset += codewordSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
//try {
|
||||||
|
let rsDecoder = ReedSolomonDecoder::new(gf);
|
||||||
|
rsDecoder.decode(
|
||||||
|
&mut dataWords,
|
||||||
|
(numCodewords - numDataCodewords as usize) as i32,
|
||||||
|
);
|
||||||
|
//} catch (ReedSolomonException ex) {
|
||||||
|
//throw FormatException.getFormatInstance(ex);
|
||||||
|
//}
|
||||||
|
|
||||||
|
// Now perform the unstuffing operation.
|
||||||
|
// First, count how many bits are going to be thrown out as stuffing
|
||||||
|
let mask = (1 << codewordSize) - 1;
|
||||||
|
let mut stuffedBits = 0;
|
||||||
|
for i in 0..numDataCodewords as usize {
|
||||||
|
// for (int i = 0; i < numDataCodewords; i++) {
|
||||||
|
let dataWord = dataWords[i];
|
||||||
|
if dataWord == 0 || dataWord == mask {
|
||||||
|
return Err(Exceptions::FormatException(
|
||||||
|
"dataWord == 0 || dataWord == mask".to_owned(),
|
||||||
|
));
|
||||||
|
//throw FormatException.getFormatInstance();
|
||||||
|
} else if dataWord == 1 || dataWord == mask - 1 {
|
||||||
|
stuffedBits += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Now, actually unpack the bits and remove the stuffing
|
||||||
|
let mut correctedBits =
|
||||||
|
vec![false; (numDataCodewords * codewordSize as u32 - stuffedBits) as usize];
|
||||||
|
let mut index = 0;
|
||||||
|
for i in 0..numDataCodewords as usize {
|
||||||
|
// for (int i = 0; i < numDataCodewords; i++) {
|
||||||
|
let dataWord = dataWords[i];
|
||||||
|
if dataWord == 1 || dataWord == mask - 1 {
|
||||||
|
// next codewordSize-1 bits are all zeros or all ones
|
||||||
|
correctedBits.splice(
|
||||||
|
index..index + codewordSize - 1,
|
||||||
|
vec![dataWord > 1; codewordSize],
|
||||||
|
);
|
||||||
|
// Arrays.fill(correctedBits, index, index + codewordSize - 1, dataWord > 1);
|
||||||
|
index += codewordSize - 1;
|
||||||
|
} else {
|
||||||
|
for bit in (0..codewordSize).rev() {
|
||||||
|
// for (int bit = codewordSize - 1; bit >= 0; --bit) {
|
||||||
|
correctedBits[index] = (dataWord & (1 << bit)) != 0;
|
||||||
|
index += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(CorrectedBitsRXingResult::new(
|
||||||
|
correctedBits,
|
||||||
|
(100 * (numCodewords - numDataCodewords as usize) / numCodewords) as u32,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the array of bits from an Aztec Code matrix
|
||||||
|
*
|
||||||
|
* @return the array of bits
|
||||||
|
*/
|
||||||
|
fn extractBits(ddata: &AztecDetectorRXingResult, matrix: &BitMatrix) -> Vec<bool> {
|
||||||
|
let compact = ddata.isCompact();
|
||||||
|
let layers = ddata.getNbLayers();
|
||||||
|
let baseMatrixSize = ((if compact { 11 } else { 14 }) + layers * 4) as usize; // not including alignment lines
|
||||||
|
let mut alignmentMap = vec![0u32; baseMatrixSize];
|
||||||
|
let mut rawbits = vec![false; totalBitsInLayer(layers as usize, compact)];
|
||||||
|
|
||||||
|
if compact {
|
||||||
|
for i in 0..alignmentMap.len() {
|
||||||
|
// for (int i = 0; i < alignmentMap.length; i++) {
|
||||||
|
alignmentMap[i] = i as u32;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let matrixSize = baseMatrixSize + 1 + 2 * ((baseMatrixSize / 2 - 1) / 15);
|
||||||
|
let origCenter = baseMatrixSize / 2;
|
||||||
|
let center = matrixSize / 2;
|
||||||
|
for i in 0..origCenter {
|
||||||
|
// for (int i = 0; i < origCenter; i++) {
|
||||||
|
let newOffset = i + i / 15;
|
||||||
|
alignmentMap[origCenter - i - 1] = (center - newOffset - 1) as u32;
|
||||||
|
alignmentMap[origCenter + i] = (center + newOffset + 1) as u32;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let mut rowOffset = 0;
|
||||||
|
for i in 0..layers {
|
||||||
|
// for (int i = 0, rowOffset = 0; i < layers; i++) {
|
||||||
|
let rowSize = (layers - i) * 4 + (if compact { 9 } else { 12 });
|
||||||
|
// The top-left most point of this layer is <low, low> (not including alignment lines)
|
||||||
|
let low = i * 2;
|
||||||
|
// The bottom-right most point of this layer is <high, high> (not including alignment lines)
|
||||||
|
let high = baseMatrixSize as u32 - 1 - low;
|
||||||
|
// We pull bits from the two 2 x rowSize columns and two rowSize x 2 rows
|
||||||
|
for j in 0..rowSize {
|
||||||
|
// for (int j = 0; j < rowSize; j++) {
|
||||||
|
let columnOffset = j * 2;
|
||||||
|
for k in 0..2 {
|
||||||
|
// for (int k = 0; k < 2; k++) {
|
||||||
|
// left column
|
||||||
|
rawbits[(rowOffset + columnOffset + k) as usize] = matrix.get(
|
||||||
|
alignmentMap[(low + k) as usize],
|
||||||
|
alignmentMap[(low + j) as usize],
|
||||||
|
);
|
||||||
|
// bottom row
|
||||||
|
rawbits[(rowOffset + 2 * rowSize + columnOffset + k) as usize] = matrix.get(
|
||||||
|
alignmentMap[(low + j) as usize],
|
||||||
|
alignmentMap[(high - k) as usize],
|
||||||
|
);
|
||||||
|
// right column
|
||||||
|
rawbits[(rowOffset + 4 * rowSize + columnOffset + k) as usize] = matrix.get(
|
||||||
|
alignmentMap[(high - k) as usize],
|
||||||
|
alignmentMap[(high - j) as usize],
|
||||||
|
);
|
||||||
|
// top row
|
||||||
|
rawbits[(rowOffset + 6 * rowSize + columnOffset + k) as usize] = matrix.get(
|
||||||
|
alignmentMap[(high - j) as usize],
|
||||||
|
alignmentMap[(low + k) as usize],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rowOffset += rowSize * 8;
|
||||||
|
}
|
||||||
|
return rawbits;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads a code of given length and at given index in an array of bits
|
||||||
|
*/
|
||||||
|
fn readCode(rawbits: &[bool], startIndex: usize, length: usize) -> u32 {
|
||||||
|
let mut res = 0;
|
||||||
|
for i in startIndex..length {
|
||||||
|
// for (int i = startIndex; i < startIndex + length; i++) {
|
||||||
|
res <<= 1;
|
||||||
|
if rawbits[i] {
|
||||||
|
res |= 0x01;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads a code of length 8 in an array of bits, padding with zeros
|
||||||
|
*/
|
||||||
|
fn readByte(rawbits: &[bool], startIndex: usize) -> u8 {
|
||||||
|
let n = rawbits.len() - startIndex;
|
||||||
|
if n >= 8 {
|
||||||
|
return readCode(rawbits, startIndex, 8) as u8;
|
||||||
|
}
|
||||||
|
return (readCode(rawbits, startIndex, n) << (8 - n)) as u8;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Packs a bit array into bytes, most significant bit first
|
||||||
|
*/
|
||||||
|
pub fn convertBoolArrayToByteArray(boolArr: &[bool]) -> Vec<u8> {
|
||||||
|
let mut byteArr = vec![0u8; (boolArr.len() + 7) / 8];
|
||||||
|
for i in 0..byteArr.len() {
|
||||||
|
// for (int i = 0; i < byteArr.length; i++) {
|
||||||
|
byteArr[i] = readByte(boolArr, 8 * i);
|
||||||
|
}
|
||||||
|
return byteArr;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn totalBitsInLayer(layers: usize, compact: bool) -> usize {
|
||||||
|
(if compact { 88 } else { 112 } + 16 * layers) * layers
|
||||||
|
// return ((compact ? 88 : 112) + 16 * layers) * layers;
|
||||||
|
}
|
||||||
@@ -1,443 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2010 ZXing authors
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.google.zxing.aztec.decoder;
|
|
||||||
|
|
||||||
import com.google.zxing.FormatException;
|
|
||||||
import com.google.zxing.aztec.AztecDetectorRXingResult;
|
|
||||||
import com.google.zxing.common.BitMatrix;
|
|
||||||
import com.google.zxing.common.CharacterSetECI;
|
|
||||||
import com.google.zxing.common.DecoderRXingResult;
|
|
||||||
import com.google.zxing.common.reedsolomon.GenericGF;
|
|
||||||
import com.google.zxing.common.reedsolomon.ReedSolomonDecoder;
|
|
||||||
import com.google.zxing.common.reedsolomon.ReedSolomonException;
|
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
import java.io.UnsupportedEncodingException;
|
|
||||||
import java.nio.charset.Charset;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.util.Arrays;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>The main class which implements Aztec Code decoding -- as opposed to locating and extracting
|
|
||||||
* the Aztec Code from an image.</p>
|
|
||||||
*
|
|
||||||
* @author David Olivier
|
|
||||||
*/
|
|
||||||
public final class Decoder {
|
|
||||||
|
|
||||||
private enum Table {
|
|
||||||
UPPER,
|
|
||||||
LOWER,
|
|
||||||
MIXED,
|
|
||||||
DIGIT,
|
|
||||||
PUNCT,
|
|
||||||
BINARY
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final String[] UPPER_TABLE = {
|
|
||||||
"CTRL_PS", " ", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P",
|
|
||||||
"Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "CTRL_LL", "CTRL_ML", "CTRL_DL", "CTRL_BS"
|
|
||||||
};
|
|
||||||
|
|
||||||
private static final String[] LOWER_TABLE = {
|
|
||||||
"CTRL_PS", " ", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p",
|
|
||||||
"q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "CTRL_US", "CTRL_ML", "CTRL_DL", "CTRL_BS"
|
|
||||||
};
|
|
||||||
|
|
||||||
private static final String[] MIXED_TABLE = {
|
|
||||||
"CTRL_PS", " ", "\1", "\2", "\3", "\4", "\5", "\6", "\7", "\b", "\t", "\n",
|
|
||||||
"\13", "\f", "\r", "\33", "\34", "\35", "\36", "\37", "@", "\\", "^", "_",
|
|
||||||
"`", "|", "~", "\177", "CTRL_LL", "CTRL_UL", "CTRL_PL", "CTRL_BS"
|
|
||||||
};
|
|
||||||
|
|
||||||
private static final String[] PUNCT_TABLE = {
|
|
||||||
"FLG(n)", "\r", "\r\n", ". ", ", ", ": ", "!", "\"", "#", "$", "%", "&", "'", "(", ")",
|
|
||||||
"*", "+", ",", "-", ".", "/", ":", ";", "<", "=", ">", "?", "[", "]", "{", "}", "CTRL_UL"
|
|
||||||
};
|
|
||||||
|
|
||||||
private static final String[] DIGIT_TABLE = {
|
|
||||||
"CTRL_PS", " ", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", ",", ".", "CTRL_UL", "CTRL_US"
|
|
||||||
};
|
|
||||||
|
|
||||||
private static final Charset DEFAULT_ENCODING = StandardCharsets.ISO_8859_1;
|
|
||||||
|
|
||||||
private AztecDetectorRXingResult ddata;
|
|
||||||
|
|
||||||
public DecoderRXingResult decode(AztecDetectorRXingResult detectorRXingResult) throws FormatException {
|
|
||||||
ddata = detectorRXingResult;
|
|
||||||
BitMatrix matrix = detectorRXingResult.getBits();
|
|
||||||
boolean[] rawbits = extractBits(matrix);
|
|
||||||
CorrectedBitsRXingResult correctedBits = correctBits(rawbits);
|
|
||||||
byte[] rawBytes = convertBoolArrayToByteArray(correctedBits.correctBits);
|
|
||||||
String result = getEncodedData(correctedBits.correctBits);
|
|
||||||
DecoderRXingResult decoderRXingResult =
|
|
||||||
new DecoderRXingResult(rawBytes, result, null, String.format("%d%%", correctedBits.ecLevel));
|
|
||||||
decoderRXingResult.setNumBits(correctedBits.correctBits.length);
|
|
||||||
return decoderRXingResult;
|
|
||||||
}
|
|
||||||
|
|
||||||
// This method is used for testing the high-level encoder
|
|
||||||
public static String highLevelDecode(boolean[] correctedBits) throws FormatException {
|
|
||||||
return getEncodedData(correctedBits);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the string encoded in the aztec code bits
|
|
||||||
*
|
|
||||||
* @return the decoded string
|
|
||||||
*/
|
|
||||||
private static String getEncodedData(boolean[] correctedBits) throws FormatException {
|
|
||||||
int endIndex = correctedBits.length;
|
|
||||||
Table latchTable = Table.UPPER; // table most recently latched to
|
|
||||||
Table shiftTable = Table.UPPER; // table to use for the next read
|
|
||||||
|
|
||||||
// Final decoded string result
|
|
||||||
// (correctedBits-5) / 4 is an upper bound on the size (all-digit result)
|
|
||||||
StringBuilder result = new StringBuilder((correctedBits.length - 5) / 4);
|
|
||||||
|
|
||||||
// Intermediary buffer of decoded bytes, which is decoded into a string and flushed
|
|
||||||
// when character encoding changes (ECI) or input ends.
|
|
||||||
ByteArrayOutputStream decodedBytes = new ByteArrayOutputStream();
|
|
||||||
Charset encoding = DEFAULT_ENCODING;
|
|
||||||
|
|
||||||
int index = 0;
|
|
||||||
while (index < endIndex) {
|
|
||||||
if (shiftTable == Table.BINARY) {
|
|
||||||
if (endIndex - index < 5) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
int length = readCode(correctedBits, index, 5);
|
|
||||||
index += 5;
|
|
||||||
if (length == 0) {
|
|
||||||
if (endIndex - index < 11) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
length = readCode(correctedBits, index, 11) + 31;
|
|
||||||
index += 11;
|
|
||||||
}
|
|
||||||
for (int charCount = 0; charCount < length; charCount++) {
|
|
||||||
if (endIndex - index < 8) {
|
|
||||||
index = endIndex; // Force outer loop to exit
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
int code = readCode(correctedBits, index, 8);
|
|
||||||
decodedBytes.write((byte) code);
|
|
||||||
index += 8;
|
|
||||||
}
|
|
||||||
// Go back to whatever mode we had been in
|
|
||||||
shiftTable = latchTable;
|
|
||||||
} else {
|
|
||||||
int size = shiftTable == Table.DIGIT ? 4 : 5;
|
|
||||||
if (endIndex - index < size) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
int code = readCode(correctedBits, index, size);
|
|
||||||
index += size;
|
|
||||||
String str = getCharacter(shiftTable, code);
|
|
||||||
if ("FLG(n)".equals(str)) {
|
|
||||||
if (endIndex - index < 3) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
int n = readCode(correctedBits, index, 3);
|
|
||||||
index += 3;
|
|
||||||
// flush bytes, FLG changes state
|
|
||||||
try {
|
|
||||||
result.append(decodedBytes.toString(encoding.name()));
|
|
||||||
} catch (UnsupportedEncodingException uee) {
|
|
||||||
throw new IllegalStateException(uee);
|
|
||||||
}
|
|
||||||
decodedBytes.reset();
|
|
||||||
switch (n) {
|
|
||||||
case 0:
|
|
||||||
result.append((char) 29); // translate FNC1 as ASCII 29
|
|
||||||
break;
|
|
||||||
case 7:
|
|
||||||
throw FormatException.getFormatInstance(); // FLG(7) is reserved and illegal
|
|
||||||
default:
|
|
||||||
// ECI is decimal integer encoded as 1-6 codes in DIGIT mode
|
|
||||||
int eci = 0;
|
|
||||||
if (endIndex - index < 4 * n) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
while (n-- > 0) {
|
|
||||||
int nextDigit = readCode(correctedBits, index, 4);
|
|
||||||
index += 4;
|
|
||||||
if (nextDigit < 2 || nextDigit > 11) {
|
|
||||||
throw FormatException.getFormatInstance(); // Not a decimal digit
|
|
||||||
}
|
|
||||||
eci = eci * 10 + (nextDigit - 2);
|
|
||||||
}
|
|
||||||
CharacterSetECI charsetECI = CharacterSetECI.getCharacterSetECIByValue(eci);
|
|
||||||
if (charsetECI == null) {
|
|
||||||
throw FormatException.getFormatInstance();
|
|
||||||
}
|
|
||||||
encoding = charsetECI.getCharset();
|
|
||||||
}
|
|
||||||
// Go back to whatever mode we had been in
|
|
||||||
shiftTable = latchTable;
|
|
||||||
} else if (str.startsWith("CTRL_")) {
|
|
||||||
// Table changes
|
|
||||||
// ISO/IEC 24778:2008 prescribes ending a shift sequence in the mode from which it was invoked.
|
|
||||||
// That's including when that mode is a shift.
|
|
||||||
// Our test case dlusbs.png for issue #642 exercises that.
|
|
||||||
latchTable = shiftTable; // Latch the current mode, so as to return to Upper after U/S B/S
|
|
||||||
shiftTable = getTable(str.charAt(5));
|
|
||||||
if (str.charAt(6) == 'L') {
|
|
||||||
latchTable = shiftTable;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Though stored as a table of strings for convenience, codes actually represent 1 or 2 *bytes*.
|
|
||||||
byte[] b = str.getBytes(StandardCharsets.US_ASCII);
|
|
||||||
decodedBytes.write(b, 0, b.length);
|
|
||||||
// Go back to whatever mode we had been in
|
|
||||||
shiftTable = latchTable;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
result.append(decodedBytes.toString(encoding.name()));
|
|
||||||
} catch (UnsupportedEncodingException uee) {
|
|
||||||
// can't happen
|
|
||||||
throw new IllegalStateException(uee);
|
|
||||||
}
|
|
||||||
return result.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* gets the table corresponding to the char passed
|
|
||||||
*/
|
|
||||||
private static Table getTable(char t) {
|
|
||||||
switch (t) {
|
|
||||||
case 'L':
|
|
||||||
return Table.LOWER;
|
|
||||||
case 'P':
|
|
||||||
return Table.PUNCT;
|
|
||||||
case 'M':
|
|
||||||
return Table.MIXED;
|
|
||||||
case 'D':
|
|
||||||
return Table.DIGIT;
|
|
||||||
case 'B':
|
|
||||||
return Table.BINARY;
|
|
||||||
case 'U':
|
|
||||||
default:
|
|
||||||
return Table.UPPER;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the character (or string) corresponding to the passed code in the given table
|
|
||||||
*
|
|
||||||
* @param table the table used
|
|
||||||
* @param code the code of the character
|
|
||||||
*/
|
|
||||||
private static String getCharacter(Table table, int code) {
|
|
||||||
switch (table) {
|
|
||||||
case UPPER:
|
|
||||||
return UPPER_TABLE[code];
|
|
||||||
case LOWER:
|
|
||||||
return LOWER_TABLE[code];
|
|
||||||
case MIXED:
|
|
||||||
return MIXED_TABLE[code];
|
|
||||||
case PUNCT:
|
|
||||||
return PUNCT_TABLE[code];
|
|
||||||
case DIGIT:
|
|
||||||
return DIGIT_TABLE[code];
|
|
||||||
default:
|
|
||||||
// Should not reach here.
|
|
||||||
throw new IllegalStateException("Bad table");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static final class CorrectedBitsRXingResult {
|
|
||||||
private final boolean[] correctBits;
|
|
||||||
private final int ecLevel;
|
|
||||||
|
|
||||||
CorrectedBitsRXingResult(boolean[] correctBits, int ecLevel) {
|
|
||||||
this.correctBits = correctBits;
|
|
||||||
this.ecLevel = ecLevel;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>Performs RS error correction on an array of bits.</p>
|
|
||||||
*
|
|
||||||
* @return the corrected array
|
|
||||||
* @throws FormatException if the input contains too many errors
|
|
||||||
*/
|
|
||||||
private CorrectedBitsRXingResult correctBits(boolean[] rawbits) throws FormatException {
|
|
||||||
GenericGF gf;
|
|
||||||
int codewordSize;
|
|
||||||
|
|
||||||
if (ddata.getNbLayers() <= 2) {
|
|
||||||
codewordSize = 6;
|
|
||||||
gf = GenericGF.AZTEC_DATA_6;
|
|
||||||
} else if (ddata.getNbLayers() <= 8) {
|
|
||||||
codewordSize = 8;
|
|
||||||
gf = GenericGF.AZTEC_DATA_8;
|
|
||||||
} else if (ddata.getNbLayers() <= 22) {
|
|
||||||
codewordSize = 10;
|
|
||||||
gf = GenericGF.AZTEC_DATA_10;
|
|
||||||
} else {
|
|
||||||
codewordSize = 12;
|
|
||||||
gf = GenericGF.AZTEC_DATA_12;
|
|
||||||
}
|
|
||||||
|
|
||||||
int numDataCodewords = ddata.getNbDatablocks();
|
|
||||||
int numCodewords = rawbits.length / codewordSize;
|
|
||||||
if (numCodewords < numDataCodewords) {
|
|
||||||
throw FormatException.getFormatInstance();
|
|
||||||
}
|
|
||||||
int offset = rawbits.length % codewordSize;
|
|
||||||
|
|
||||||
int[] dataWords = new int[numCodewords];
|
|
||||||
for (int i = 0; i < numCodewords; i++, offset += codewordSize) {
|
|
||||||
dataWords[i] = readCode(rawbits, offset, codewordSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
ReedSolomonDecoder rsDecoder = new ReedSolomonDecoder(gf);
|
|
||||||
rsDecoder.decode(dataWords, numCodewords - numDataCodewords);
|
|
||||||
} catch (ReedSolomonException ex) {
|
|
||||||
throw FormatException.getFormatInstance(ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now perform the unstuffing operation.
|
|
||||||
// First, count how many bits are going to be thrown out as stuffing
|
|
||||||
int mask = (1 << codewordSize) - 1;
|
|
||||||
int stuffedBits = 0;
|
|
||||||
for (int i = 0; i < numDataCodewords; i++) {
|
|
||||||
int dataWord = dataWords[i];
|
|
||||||
if (dataWord == 0 || dataWord == mask) {
|
|
||||||
throw FormatException.getFormatInstance();
|
|
||||||
} else if (dataWord == 1 || dataWord == mask - 1) {
|
|
||||||
stuffedBits++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Now, actually unpack the bits and remove the stuffing
|
|
||||||
boolean[] correctedBits = new boolean[numDataCodewords * codewordSize - stuffedBits];
|
|
||||||
int index = 0;
|
|
||||||
for (int i = 0; i < numDataCodewords; i++) {
|
|
||||||
int dataWord = dataWords[i];
|
|
||||||
if (dataWord == 1 || dataWord == mask - 1) {
|
|
||||||
// next codewordSize-1 bits are all zeros or all ones
|
|
||||||
Arrays.fill(correctedBits, index, index + codewordSize - 1, dataWord > 1);
|
|
||||||
index += codewordSize - 1;
|
|
||||||
} else {
|
|
||||||
for (int bit = codewordSize - 1; bit >= 0; --bit) {
|
|
||||||
correctedBits[index++] = (dataWord & (1 << bit)) != 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return new CorrectedBitsRXingResult(correctedBits, 100 * (numCodewords - numDataCodewords) / numCodewords);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the array of bits from an Aztec Code matrix
|
|
||||||
*
|
|
||||||
* @return the array of bits
|
|
||||||
*/
|
|
||||||
private boolean[] extractBits(BitMatrix matrix) {
|
|
||||||
boolean compact = ddata.isCompact();
|
|
||||||
int layers = ddata.getNbLayers();
|
|
||||||
int baseMatrixSize = (compact ? 11 : 14) + layers * 4; // not including alignment lines
|
|
||||||
int[] alignmentMap = new int[baseMatrixSize];
|
|
||||||
boolean[] rawbits = new boolean[totalBitsInLayer(layers, compact)];
|
|
||||||
|
|
||||||
if (compact) {
|
|
||||||
for (int i = 0; i < alignmentMap.length; i++) {
|
|
||||||
alignmentMap[i] = i;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
int matrixSize = baseMatrixSize + 1 + 2 * ((baseMatrixSize / 2 - 1) / 15);
|
|
||||||
int origCenter = baseMatrixSize / 2;
|
|
||||||
int center = matrixSize / 2;
|
|
||||||
for (int i = 0; i < origCenter; i++) {
|
|
||||||
int newOffset = i + i / 15;
|
|
||||||
alignmentMap[origCenter - i - 1] = center - newOffset - 1;
|
|
||||||
alignmentMap[origCenter + i] = center + newOffset + 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (int i = 0, rowOffset = 0; i < layers; i++) {
|
|
||||||
int rowSize = (layers - i) * 4 + (compact ? 9 : 12);
|
|
||||||
// The top-left most point of this layer is <low, low> (not including alignment lines)
|
|
||||||
int low = i * 2;
|
|
||||||
// The bottom-right most point of this layer is <high, high> (not including alignment lines)
|
|
||||||
int high = baseMatrixSize - 1 - low;
|
|
||||||
// We pull bits from the two 2 x rowSize columns and two rowSize x 2 rows
|
|
||||||
for (int j = 0; j < rowSize; j++) {
|
|
||||||
int columnOffset = j * 2;
|
|
||||||
for (int k = 0; k < 2; k++) {
|
|
||||||
// left column
|
|
||||||
rawbits[rowOffset + columnOffset + k] =
|
|
||||||
matrix.get(alignmentMap[low + k], alignmentMap[low + j]);
|
|
||||||
// bottom row
|
|
||||||
rawbits[rowOffset + 2 * rowSize + columnOffset + k] =
|
|
||||||
matrix.get(alignmentMap[low + j], alignmentMap[high - k]);
|
|
||||||
// right column
|
|
||||||
rawbits[rowOffset + 4 * rowSize + columnOffset + k] =
|
|
||||||
matrix.get(alignmentMap[high - k], alignmentMap[high - j]);
|
|
||||||
// top row
|
|
||||||
rawbits[rowOffset + 6 * rowSize + columnOffset + k] =
|
|
||||||
matrix.get(alignmentMap[high - j], alignmentMap[low + k]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
rowOffset += rowSize * 8;
|
|
||||||
}
|
|
||||||
return rawbits;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reads a code of given length and at given index in an array of bits
|
|
||||||
*/
|
|
||||||
private static int readCode(boolean[] rawbits, int startIndex, int length) {
|
|
||||||
int res = 0;
|
|
||||||
for (int i = startIndex; i < startIndex + length; i++) {
|
|
||||||
res <<= 1;
|
|
||||||
if (rawbits[i]) {
|
|
||||||
res |= 0x01;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reads a code of length 8 in an array of bits, padding with zeros
|
|
||||||
*/
|
|
||||||
private static byte readByte(boolean[] rawbits, int startIndex) {
|
|
||||||
int n = rawbits.length - startIndex;
|
|
||||||
if (n >= 8) {
|
|
||||||
return (byte) readCode(rawbits, startIndex, 8);
|
|
||||||
}
|
|
||||||
return (byte) (readCode(rawbits, startIndex, n) << (8 - n));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Packs a bit array into bytes, most significant bit first
|
|
||||||
*/
|
|
||||||
static byte[] convertBoolArrayToByteArray(boolean[] boolArr) {
|
|
||||||
byte[] byteArr = new byte[(boolArr.length + 7) / 8];
|
|
||||||
for (int i = 0; i < byteArr.length; i++) {
|
|
||||||
byteArr[i] = readByte(boolArr, 8 * i);
|
|
||||||
}
|
|
||||||
return byteArr;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int totalBitsInLayer(int layers, boolean compact) {
|
|
||||||
return ((compact ? 88 : 112) + 16 * layers) * layers;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -14,18 +14,27 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.google.zxing.aztec.detector;
|
// package com.google.zxing.aztec.detector;
|
||||||
|
|
||||||
import com.google.zxing.NotFoundException;
|
// import com.google.zxing.NotFoundException;
|
||||||
import com.google.zxing.RXingResultPoint;
|
// import com.google.zxing.RXingResultPoint;
|
||||||
import com.google.zxing.aztec.AztecDetectorRXingResult;
|
// import com.google.zxing.aztec.AztecDetectorRXingResult;
|
||||||
import com.google.zxing.common.BitMatrix;
|
// import com.google.zxing.common.BitMatrix;
|
||||||
import com.google.zxing.common.GridSampler;
|
// import com.google.zxing.common.GridSampler;
|
||||||
import com.google.zxing.common.detector.MathUtils;
|
// import com.google.zxing.common.detector.MathUtils;
|
||||||
import com.google.zxing.common.detector.WhiteRectangleDetector;
|
// import com.google.zxing.common.detector.WhiteRectangleDetector;
|
||||||
import com.google.zxing.common.reedsolomon.GenericGF;
|
// import com.google.zxing.common.reedsolomon.GenericGF;
|
||||||
import com.google.zxing.common.reedsolomon.ReedSolomonDecoder;
|
// import com.google.zxing.common.reedsolomon.ReedSolomonDecoder;
|
||||||
import com.google.zxing.common.reedsolomon.ReedSolomonException;
|
// import com.google.zxing.common.reedsolomon.ReedSolomonException;
|
||||||
|
|
||||||
|
use crate::common::BitMatrix;
|
||||||
|
|
||||||
|
const EXPECTED_CORNER_BITS : [u16;4]= [
|
||||||
|
0xee0, // 07340 XXX .XX X.. ...
|
||||||
|
0x1dc, // 00734 ... XXX .XX X..
|
||||||
|
0x83b, // 04073 X.. ... XXX .XX
|
||||||
|
0x707, // 03407 .XX X.. ... XXX
|
||||||
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Encapsulates logic that can detect an Aztec Code in an image, even if the Aztec Code
|
* Encapsulates logic that can detect an Aztec Code in an image, even if the Aztec Code
|
||||||
@@ -34,25 +43,27 @@ import com.google.zxing.common.reedsolomon.ReedSolomonException;
|
|||||||
* @author David Olivier
|
* @author David Olivier
|
||||||
* @author Frank Yellin
|
* @author Frank Yellin
|
||||||
*/
|
*/
|
||||||
public final class Detector {
|
pub struct Detector {
|
||||||
|
image:BitMatrix,
|
||||||
|
|
||||||
private static final int[] EXPECTED_CORNER_BITS = {
|
compact:bool,
|
||||||
0xee0, // 07340 XXX .XX X.. ...
|
nbLayers:u32,
|
||||||
0x1dc, // 00734 ... XXX .XX X..
|
nbDataBlocks:u32,
|
||||||
0x83b, // 04073 X.. ... XXX .XX
|
nbCenterLayers:u32,
|
||||||
0x707, // 03407 .XX X.. ... XXX
|
shift:u32,
|
||||||
};
|
}
|
||||||
|
|
||||||
private final BitMatrix image;
|
impl Detector {
|
||||||
|
|
||||||
private boolean compact;
|
pub fn new( image:BitMatrix) -> Self{
|
||||||
private int nbLayers;
|
Self{
|
||||||
private int nbDataBlocks;
|
image,
|
||||||
private int nbCenterLayers;
|
compact: false,
|
||||||
private int shift;
|
nbLayers: 0,
|
||||||
|
nbDataBlocks: 0,
|
||||||
public Detector(BitMatrix image) {
|
nbCenterLayers: 0,
|
||||||
this.image = image;
|
shift: 0,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public AztecDetectorRXingResult detect() throws NotFoundException {
|
public AztecDetectorRXingResult detect() throws NotFoundException {
|
||||||
10
src/aztec/mod.rs
Normal file
10
src/aztec/mod.rs
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
mod AztecDetectorResult;
|
||||||
|
pub mod decoder;
|
||||||
|
// pub mod detector;
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod DecoderTest;
|
||||||
|
// #[cfg(test)]
|
||||||
|
// mod EncoderTest;
|
||||||
|
|
||||||
|
mod shared_test_methods;
|
||||||
32
src/aztec/shared_test_methods.rs
Normal file
32
src/aztec/shared_test_methods.rs
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
use regex::Regex;
|
||||||
|
|
||||||
|
use crate::common::BitArray;
|
||||||
|
|
||||||
|
const SPACES :&str= "\\s+";
|
||||||
|
const DOTX : &str = "[^.X]";
|
||||||
|
|
||||||
|
pub fn toBitArray( bits:&str) -> BitArray{
|
||||||
|
let mut ba_in = BitArray::new();
|
||||||
|
let replacer_regex = Regex::new(DOTX).unwrap();
|
||||||
|
let str = replacer_regex.replace_all(bits, "");
|
||||||
|
for aStr in str.chars() {
|
||||||
|
// for (char aStr : str) {
|
||||||
|
ba_in.appendBit(aStr == 'X');
|
||||||
|
}
|
||||||
|
|
||||||
|
ba_in
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn toBooleanArray( bitArray:&BitArray) ->Vec<bool>{
|
||||||
|
let mut result = vec![false;bitArray.getSize()];
|
||||||
|
for i in 0..result.len() {
|
||||||
|
// for (int i = 0; i < result.length; i++) {
|
||||||
|
result[i] = bitArray.get(i);
|
||||||
|
}
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn stripSpace( s:&str) -> String{
|
||||||
|
let replacer_regex = Regex::new(SPACES).unwrap();
|
||||||
|
replacer_regex.replace_all(s, "").to_string()
|
||||||
|
}
|
||||||
@@ -719,27 +719,17 @@ impl fmt::Display for BitArray {
|
|||||||
*
|
*
|
||||||
* @author Sean Owen
|
* @author Sean Owen
|
||||||
*/
|
*/
|
||||||
pub struct DetectorRXingResult {
|
pub trait DetectorRXingResult {
|
||||||
bits: BitMatrix,
|
|
||||||
points: Vec<RXingResultPoint>,
|
fn getBits(&self) -> &BitMatrix;
|
||||||
|
|
||||||
|
fn getPoints(&self) -> &Vec<RXingResultPoint>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DetectorRXingResult {
|
// pub struct DetectorRXingResult {
|
||||||
pub fn new(bits: BitMatrix, points: Vec<RXingResultPoint>) -> Self {
|
// bits: BitMatrix,
|
||||||
Self {
|
// points: Vec<RXingResultPoint>,
|
||||||
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
|
* Copyright 2007 ZXing authors
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
mod common;
|
mod common;
|
||||||
mod exceptions;
|
mod exceptions;
|
||||||
mod client;
|
mod client;
|
||||||
|
mod aztec;
|
||||||
|
|
||||||
#[cfg(feature="image")]
|
#[cfg(feature="image")]
|
||||||
mod BufferedImageLuminanceSource;
|
mod BufferedImageLuminanceSource;
|
||||||
@@ -840,7 +841,7 @@ impl PartialEq for RXingResultPoint {
|
|||||||
}
|
}
|
||||||
impl Eq for RXingResultPoint {}
|
impl Eq for RXingResultPoint {}
|
||||||
impl RXingResultPoint {
|
impl RXingResultPoint {
|
||||||
pub fn new(x: f32, y: f32) -> Self {
|
pub const fn new(x: f32, y: f32) -> Self {
|
||||||
Self { x, y }
|
Self { x, y }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user