mirror of
https://github.com/starovoid/rxing.git
synced 2026-07-27 21:02:35 +00:00
progress on aztec
This commit is contained in:
@@ -56,17 +56,17 @@ use crate::common::BitMatrix;
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn testErrorInParameterLocatorNotCompact() {
|
fn testErrorInParameterLocatorNotCompact() {
|
||||||
String alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYabcdefghijklmnopqrstuvwxyz";
|
let alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYabcdefghijklmnopqrstuvwxyz";
|
||||||
testErrorInParameterLocator(alphabet + alphabet + alphabet);
|
testErrorInParameterLocator(&format!("{}{}{}",alphabet , alphabet , alphabet));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test that we can tolerate errors in the parameter locator bits
|
// Test that we can tolerate errors in the parameter locator bits
|
||||||
fn testErrorInParameterLocator( data:&str) {
|
fn testErrorInParameterLocator( data:&str) {
|
||||||
AztecCode aztec = Encoder.encode(data, 25, Encoder.DEFAULT_AZTEC_LAYERS);
|
let aztec = Encoder.encode(data, 25, Encoder.DEFAULT_AZTEC_LAYERS);
|
||||||
Random random = new Random(aztec.getMatrix().hashCode()); // pseudo-random, but deterministic
|
let random = new Random(aztec.getMatrix().hashCode()); // pseudo-random, but deterministic
|
||||||
int layers = aztec.getLayers();
|
let layers = aztec.getLayers();
|
||||||
boolean compact = aztec.isCompact();
|
let compact = aztec.isCompact();
|
||||||
List<Point> orientationPoints = getOrientationPoints(aztec);
|
let orientationPoints = getOrientationPoints(aztec);
|
||||||
for (boolean isMirror : new boolean[] { false, true }) {
|
for (boolean isMirror : new boolean[] { false, true }) {
|
||||||
for (BitMatrix matrix : getRotations(aztec.getMatrix())) {
|
for (BitMatrix matrix : getRotations(aztec.getMatrix())) {
|
||||||
// Systematically try every possible 1- and 2-bit error.
|
// Systematically try every possible 1- and 2-bit error.
|
||||||
@@ -125,16 +125,16 @@ use crate::common::BitMatrix;
|
|||||||
|
|
||||||
// Returns a list of the four rotations of the BitMatrix.
|
// Returns a list of the four rotations of the BitMatrix.
|
||||||
fn getRotations( matrix0:&BitMatrix)-> Vec<BitMatrix> {
|
fn getRotations( matrix0:&BitMatrix)-> Vec<BitMatrix> {
|
||||||
BitMatrix matrix90 = rotateRight(matrix0);
|
let matrix90 = rotateRight(matrix0);
|
||||||
BitMatrix matrix180 = rotateRight(matrix90);
|
let matrix180 = rotateRight(matrix90);
|
||||||
BitMatrix matrix270 = rotateRight(matrix180);
|
let matrix270 = rotateRight(matrix180);
|
||||||
return Arrays.asList(matrix0, matrix90, matrix180, matrix270);
|
return Arrays.asList(matrix0, matrix90, matrix180, matrix270);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rotates a square BitMatrix to the right by 90 degrees
|
// Rotates a square BitMatrix to the right by 90 degrees
|
||||||
fn rotateRight( input:&BitMatrix) -> BitMatrix{
|
fn rotateRight( input:&BitMatrix) -> BitMatrix{
|
||||||
int width = input.getWidth();
|
let width = input.getWidth();
|
||||||
BitMatrix result = new BitMatrix(width);
|
let result = new BitMatrix(width);
|
||||||
for (int x = 0; x < width; x++) {
|
for (int x = 0; x < width; x++) {
|
||||||
for (int y = 0; y < width; y++) {
|
for (int y = 0; y < width; y++) {
|
||||||
if (input.get(x,y)) {
|
if (input.get(x,y)) {
|
||||||
@@ -149,7 +149,7 @@ use crate::common::BitMatrix;
|
|||||||
// matrix to the right, and then flipping it left-to-right
|
// matrix to the right, and then flipping it left-to-right
|
||||||
fn transpose( input:&BitMatrix) -> BitMatrix {
|
fn transpose( input:&BitMatrix) -> BitMatrix {
|
||||||
let width = input.getWidth();
|
let width = input.getWidth();
|
||||||
BitMatrix result = new BitMatrix(width);
|
let result = new BitMatrix(width);
|
||||||
for (int x = 0; x < width; x++) {
|
for (int x = 0; x < width; x++) {
|
||||||
for (int y = 0; y < width; y++) {
|
for (int y = 0; y < width; y++) {
|
||||||
if (input.get(x, y)) {
|
if (input.get(x, y)) {
|
||||||
@@ -161,8 +161,8 @@ use crate::common::BitMatrix;
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn clone( input:&BitMatrix) -> BitMatrix {
|
fn clone( input:&BitMatrix) -> BitMatrix {
|
||||||
int width = input.getWidth();
|
let width = input.getWidth();
|
||||||
BitMatrix result = new BitMatrix(width);
|
let result = new BitMatrix(width);
|
||||||
for (int x = 0; x < width; x++) {
|
for (int x = 0; x < width; x++) {
|
||||||
for (int y = 0; y < width; y++) {
|
for (int y = 0; y < width; y++) {
|
||||||
if (input.get(x,y)) {
|
if (input.get(x,y)) {
|
||||||
@@ -173,10 +173,10 @@ use crate::common::BitMatrix;
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn getOrientationPoints( code::&AztecCode) -> Vec<Point> {
|
fn getOrientationPoints( code:&AztecCode) -> Vec<Point> {
|
||||||
int center = code.getMatrix().getWidth() / 2;
|
let center = code.getMatrix().getWidth() / 2;
|
||||||
int offset = code.isCompact() ? 5 : 7;
|
let offset = code.isCompact() ? 5 : 7;
|
||||||
List<Point> result = new ArrayList<>();
|
let result = new ArrayList<>();
|
||||||
for (int xSign = -1; xSign <= 1; xSign += 2) {
|
for (int xSign = -1; xSign <= 1; xSign += 2) {
|
||||||
for (int ySign = -1; ySign <= 1; ySign += 2) {
|
for (int ySign = -1; ySign <= 1; ySign += 2) {
|
||||||
result.add(new Point(center + xSign * offset, center + ySign * offset));
|
result.add(new Point(center + xSign * offset, center + ySign * offset));
|
||||||
|
|||||||
@@ -1,89 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2013 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.encoder;
|
|
||||||
|
|
||||||
import com.google.zxing.common.BitMatrix;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Aztec 2D code representation
|
|
||||||
*
|
|
||||||
* @author Rustam Abdullaev
|
|
||||||
*/
|
|
||||||
public final class AztecCode {
|
|
||||||
|
|
||||||
private boolean compact;
|
|
||||||
private int size;
|
|
||||||
private int layers;
|
|
||||||
private int codeWords;
|
|
||||||
private BitMatrix matrix;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return {@code true} if compact instead of full mode
|
|
||||||
*/
|
|
||||||
public boolean isCompact() {
|
|
||||||
return compact;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setCompact(boolean compact) {
|
|
||||||
this.compact = compact;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return size in pixels (width and height)
|
|
||||||
*/
|
|
||||||
public int getSize() {
|
|
||||||
return size;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setSize(int size) {
|
|
||||||
this.size = size;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return number of levels
|
|
||||||
*/
|
|
||||||
public int getLayers() {
|
|
||||||
return layers;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setLayers(int layers) {
|
|
||||||
this.layers = layers;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return number of data codewords
|
|
||||||
*/
|
|
||||||
public int getCodeWords() {
|
|
||||||
return codeWords;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setCodeWords(int codeWords) {
|
|
||||||
this.codeWords = codeWords;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return the symbol image
|
|
||||||
*/
|
|
||||||
public BitMatrix getMatrix() {
|
|
||||||
return matrix;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setMatrix(BitMatrix matrix) {
|
|
||||||
this.matrix = matrix;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,61 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2013 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.encoder;
|
|
||||||
|
|
||||||
import com.google.zxing.common.BitArray;
|
|
||||||
|
|
||||||
final class BinaryShiftToken extends Token {
|
|
||||||
|
|
||||||
private final int binaryShiftStart;
|
|
||||||
private final int binaryShiftByteCount;
|
|
||||||
|
|
||||||
BinaryShiftToken(Token previous,
|
|
||||||
int binaryShiftStart,
|
|
||||||
int binaryShiftByteCount) {
|
|
||||||
super(previous);
|
|
||||||
this.binaryShiftStart = binaryShiftStart;
|
|
||||||
this.binaryShiftByteCount = binaryShiftByteCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void appendTo(BitArray bitArray, byte[] text) {
|
|
||||||
int bsbc = binaryShiftByteCount;
|
|
||||||
for (int i = 0; i < bsbc; i++) {
|
|
||||||
if (i == 0 || (i == 31 && bsbc <= 62)) {
|
|
||||||
// We need a header before the first character, and before
|
|
||||||
// character 31 when the total byte code is <= 62
|
|
||||||
bitArray.appendBits(31, 5); // BINARY_SHIFT
|
|
||||||
if (bsbc > 62) {
|
|
||||||
bitArray.appendBits(bsbc - 31, 16);
|
|
||||||
} else if (i == 0) {
|
|
||||||
// 1 <= binaryShiftByteCode <= 62
|
|
||||||
bitArray.appendBits(Math.min(bsbc, 31), 5);
|
|
||||||
} else {
|
|
||||||
// 32 <= binaryShiftCount <= 62 and i == 31
|
|
||||||
bitArray.appendBits(bsbc - 31, 5);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
bitArray.appendBits(text[binaryShiftStart + i], 8);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return "<" + binaryShiftStart + "::" + (binaryShiftStart + binaryShiftByteCount - 1) + '>';
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,45 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2013 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.encoder;
|
|
||||||
|
|
||||||
import com.google.zxing.common.BitArray;
|
|
||||||
|
|
||||||
final class SimpleToken extends Token {
|
|
||||||
|
|
||||||
// For normal words, indicates value and bitCount
|
|
||||||
private final short value;
|
|
||||||
private final short bitCount;
|
|
||||||
|
|
||||||
SimpleToken(Token previous, int value, int bitCount) {
|
|
||||||
super(previous);
|
|
||||||
this.value = (short) value;
|
|
||||||
this.bitCount = (short) bitCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
void appendTo(BitArray bitArray, byte[] text) {
|
|
||||||
bitArray.appendBits(value, bitCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
int value = this.value & ((1 << bitCount) - 1);
|
|
||||||
value |= 1 << bitCount;
|
|
||||||
return '<' + Integer.toBinaryString(value | (1 << bitCount)).substring(1) + '>';
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,195 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2013 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.encoder;
|
|
||||||
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import com.google.zxing.common.BitArray;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* State represents all information about a sequence necessary to generate the current output.
|
|
||||||
* Note that a state is immutable.
|
|
||||||
*/
|
|
||||||
final class State {
|
|
||||||
|
|
||||||
static final State INITIAL_STATE = new State(Token.EMPTY, HighLevelEncoder.MODE_UPPER, 0, 0);
|
|
||||||
|
|
||||||
// The current mode of the encoding (or the mode to which we'll return if
|
|
||||||
// we're in Binary Shift mode.
|
|
||||||
private final int mode;
|
|
||||||
// The list of tokens that we output. If we are in Binary Shift mode, this
|
|
||||||
// token list does *not* yet included the token for those bytes
|
|
||||||
private final Token token;
|
|
||||||
// If non-zero, the number of most recent bytes that should be output
|
|
||||||
// in Binary Shift mode.
|
|
||||||
private final int binaryShiftByteCount;
|
|
||||||
// The total number of bits generated (including Binary Shift).
|
|
||||||
private final int bitCount;
|
|
||||||
private final int binaryShiftCost;
|
|
||||||
|
|
||||||
private State(Token token, int mode, int binaryBytes, int bitCount) {
|
|
||||||
this.token = token;
|
|
||||||
this.mode = mode;
|
|
||||||
this.binaryShiftByteCount = binaryBytes;
|
|
||||||
this.bitCount = bitCount;
|
|
||||||
this.binaryShiftCost = calculateBinaryShiftCost(binaryBytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
int getMode() {
|
|
||||||
return mode;
|
|
||||||
}
|
|
||||||
|
|
||||||
Token getToken() {
|
|
||||||
return token;
|
|
||||||
}
|
|
||||||
|
|
||||||
int getBinaryShiftByteCount() {
|
|
||||||
return binaryShiftByteCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
int getBitCount() {
|
|
||||||
return bitCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
State appendFLGn(int eci) {
|
|
||||||
State result = shiftAndAppend(HighLevelEncoder.MODE_PUNCT, 0); // 0: FLG(n)
|
|
||||||
Token token = result.token;
|
|
||||||
int bitsAdded = 3;
|
|
||||||
if (eci < 0) {
|
|
||||||
token = token.add(0, 3); // 0: FNC1
|
|
||||||
} else if (eci > 999999) {
|
|
||||||
throw new IllegalArgumentException("ECI code must be between 0 and 999999");
|
|
||||||
} else {
|
|
||||||
byte[] eciDigits = Integer.toString(eci).getBytes(StandardCharsets.ISO_8859_1);
|
|
||||||
token = token.add(eciDigits.length, 3); // 1-6: number of ECI digits
|
|
||||||
for (byte eciDigit : eciDigits) {
|
|
||||||
token = token.add(eciDigit - '0' + 2, 4);
|
|
||||||
}
|
|
||||||
bitsAdded += eciDigits.length * 4;
|
|
||||||
}
|
|
||||||
return new State(token, mode, 0, bitCount + bitsAdded);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create a new state representing this state with a latch to a (not
|
|
||||||
// necessary different) mode, and then a code.
|
|
||||||
State latchAndAppend(int mode, int value) {
|
|
||||||
int bitCount = this.bitCount;
|
|
||||||
Token token = this.token;
|
|
||||||
if (mode != this.mode) {
|
|
||||||
int latch = HighLevelEncoder.LATCH_TABLE[this.mode][mode];
|
|
||||||
token = token.add(latch & 0xFFFF, latch >> 16);
|
|
||||||
bitCount += latch >> 16;
|
|
||||||
}
|
|
||||||
int latchModeBitCount = mode == HighLevelEncoder.MODE_DIGIT ? 4 : 5;
|
|
||||||
token = token.add(value, latchModeBitCount);
|
|
||||||
return new State(token, mode, 0, bitCount + latchModeBitCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create a new state representing this state, with a temporary shift
|
|
||||||
// to a different mode to output a single value.
|
|
||||||
State shiftAndAppend(int mode, int value) {
|
|
||||||
Token token = this.token;
|
|
||||||
int thisModeBitCount = this.mode == HighLevelEncoder.MODE_DIGIT ? 4 : 5;
|
|
||||||
// Shifts exist only to UPPER and PUNCT, both with tokens size 5.
|
|
||||||
token = token.add(HighLevelEncoder.SHIFT_TABLE[this.mode][mode], thisModeBitCount);
|
|
||||||
token = token.add(value, 5);
|
|
||||||
return new State(token, this.mode, 0, this.bitCount + thisModeBitCount + 5);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create a new state representing this state, but an additional character
|
|
||||||
// output in Binary Shift mode.
|
|
||||||
State addBinaryShiftChar(int index) {
|
|
||||||
Token token = this.token;
|
|
||||||
int mode = this.mode;
|
|
||||||
int bitCount = this.bitCount;
|
|
||||||
if (this.mode == HighLevelEncoder.MODE_PUNCT || this.mode == HighLevelEncoder.MODE_DIGIT) {
|
|
||||||
int latch = HighLevelEncoder.LATCH_TABLE[mode][HighLevelEncoder.MODE_UPPER];
|
|
||||||
token = token.add(latch & 0xFFFF, latch >> 16);
|
|
||||||
bitCount += latch >> 16;
|
|
||||||
mode = HighLevelEncoder.MODE_UPPER;
|
|
||||||
}
|
|
||||||
int deltaBitCount =
|
|
||||||
(binaryShiftByteCount == 0 || binaryShiftByteCount == 31) ? 18 :
|
|
||||||
(binaryShiftByteCount == 62) ? 9 : 8;
|
|
||||||
State result = new State(token, mode, binaryShiftByteCount + 1, bitCount + deltaBitCount);
|
|
||||||
if (result.binaryShiftByteCount == 2047 + 31) {
|
|
||||||
// The string is as long as it's allowed to be. We should end it.
|
|
||||||
result = result.endBinaryShift(index + 1);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create the state identical to this one, but we are no longer in
|
|
||||||
// Binary Shift mode.
|
|
||||||
State endBinaryShift(int index) {
|
|
||||||
if (binaryShiftByteCount == 0) {
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
Token token = this.token;
|
|
||||||
token = token.addBinaryShift(index - binaryShiftByteCount, binaryShiftByteCount);
|
|
||||||
return new State(token, mode, 0, this.bitCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns true if "this" state is better (or equal) to be in than "that"
|
|
||||||
// state under all possible circumstances.
|
|
||||||
boolean isBetterThanOrEqualTo(State other) {
|
|
||||||
int newModeBitCount = this.bitCount + (HighLevelEncoder.LATCH_TABLE[this.mode][other.mode] >> 16);
|
|
||||||
if (this.binaryShiftByteCount < other.binaryShiftByteCount) {
|
|
||||||
// add additional B/S encoding cost of other, if any
|
|
||||||
newModeBitCount += other.binaryShiftCost - this.binaryShiftCost;
|
|
||||||
} else if (this.binaryShiftByteCount > other.binaryShiftByteCount && other.binaryShiftByteCount > 0) {
|
|
||||||
// maximum possible additional cost (we end up exceeding the 31 byte boundary and other state can stay beneath it)
|
|
||||||
newModeBitCount += 10;
|
|
||||||
}
|
|
||||||
return newModeBitCount <= other.bitCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
BitArray toBitArray(byte[] text) {
|
|
||||||
List<Token> symbols = new ArrayList<>();
|
|
||||||
for (Token token = endBinaryShift(text.length).token; token != null; token = token.getPrevious()) {
|
|
||||||
symbols.add(token);
|
|
||||||
}
|
|
||||||
BitArray bitArray = new BitArray();
|
|
||||||
// Add each token to the result in forward order
|
|
||||||
for (int i = symbols.size() - 1; i >= 0; i--) {
|
|
||||||
symbols.get(i).appendTo(bitArray, text);
|
|
||||||
}
|
|
||||||
return bitArray;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return String.format("%s bits=%d bytes=%d", HighLevelEncoder.MODE_NAMES[mode], bitCount, binaryShiftByteCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int calculateBinaryShiftCost(int binaryShiftByteCount) {
|
|
||||||
if (binaryShiftByteCount > 62) {
|
|
||||||
return 21; // B/S with extended length
|
|
||||||
}
|
|
||||||
if (binaryShiftByteCount > 31) {
|
|
||||||
return 20; // two B/S
|
|
||||||
}
|
|
||||||
if (binaryShiftByteCount > 0) {
|
|
||||||
return 10; // one B/S
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2013 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.encoder;
|
|
||||||
|
|
||||||
import com.google.zxing.common.BitArray;
|
|
||||||
|
|
||||||
abstract class Token {
|
|
||||||
|
|
||||||
static final Token EMPTY = new SimpleToken(null, 0, 0);
|
|
||||||
|
|
||||||
private final Token previous;
|
|
||||||
|
|
||||||
Token(Token previous) {
|
|
||||||
this.previous = previous;
|
|
||||||
}
|
|
||||||
|
|
||||||
final Token getPrevious() {
|
|
||||||
return previous;
|
|
||||||
}
|
|
||||||
|
|
||||||
final Token add(int value, int bitCount) {
|
|
||||||
return new SimpleToken(this, value, bitCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
final Token addBinaryShift(int start, int byteCount) {
|
|
||||||
//int bitCount = (byteCount * 8) + (byteCount <= 31 ? 10 : byteCount <= 62 ? 20 : 21);
|
|
||||||
return new BinaryShiftToken(this, start, byteCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
abstract void appendTo(BitArray bitArray, byte[] text);
|
|
||||||
|
|
||||||
}
|
|
||||||
87
src/aztec/encoder/aztec_code.rs
Normal file
87
src/aztec/encoder/aztec_code.rs
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013 ZXing authors
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
use crate::common::BitMatrix;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Aztec 2D code representation
|
||||||
|
*
|
||||||
|
* @author Rustam Abdullaev
|
||||||
|
*/
|
||||||
|
pub struct AztecCode {
|
||||||
|
compact: bool,
|
||||||
|
size: u32,
|
||||||
|
layers: u32,
|
||||||
|
code_words: u32,
|
||||||
|
matrix: BitMatrix,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AztecCode {
|
||||||
|
/**
|
||||||
|
* @return {@code true} if compact instead of full mode
|
||||||
|
*/
|
||||||
|
pub fn isCompact(&self) -> bool {
|
||||||
|
self.compact
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn setCompact(&mut self, compact: bool) {
|
||||||
|
self.compact = compact;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return size in pixels (width and height)
|
||||||
|
*/
|
||||||
|
pub fn getSize(&self) -> u32 {
|
||||||
|
self.size
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn setSize(&mut self, size: u32) {
|
||||||
|
self.size = size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return number of levels
|
||||||
|
*/
|
||||||
|
pub fn getLayers(&self) -> u32 {
|
||||||
|
self.layers
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn setLayers(&mut self, layers: u32) {
|
||||||
|
self.layers = layers;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return number of data codewords
|
||||||
|
*/
|
||||||
|
pub fn getCodeWords(&self) -> u32 {
|
||||||
|
self.code_words
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn setCodeWords(&mut self, code_words: u32) {
|
||||||
|
self.code_words = code_words;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the symbol image
|
||||||
|
*/
|
||||||
|
pub fn getMatrix(&self) -> &BitMatrix {
|
||||||
|
&self.matrix
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn setMatrix(&mut self, matrix: BitMatrix) {
|
||||||
|
self.matrix = matrix;
|
||||||
|
}
|
||||||
|
}
|
||||||
72
src/aztec/encoder/binary_shift_token.rs
Normal file
72
src/aztec/encoder/binary_shift_token.rs
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013 ZXing authors
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
|
use crate::common::BitArray;
|
||||||
|
|
||||||
|
#[derive(Debug,PartialEq, Eq,Clone)]
|
||||||
|
pub struct BinaryShiftToken {
|
||||||
|
binaryShiftStart: u32,
|
||||||
|
binaryShiftByteCount: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BinaryShiftToken {
|
||||||
|
pub fn new(binaryShiftStart: u32, binaryShiftByteCount: u32) -> Self {
|
||||||
|
Self {
|
||||||
|
binaryShiftStart,
|
||||||
|
binaryShiftByteCount,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn appendTo(&self, bitArray: &mut BitArray, text: &[u8]) {
|
||||||
|
let bsbc = self.binaryShiftByteCount as usize;
|
||||||
|
for i in 0..bsbc {
|
||||||
|
// for (int i = 0; i < bsbc; i++) {
|
||||||
|
if (i == 0 || (i == 31 && bsbc <= 62)) {
|
||||||
|
// We need a header before the first character, and before
|
||||||
|
// character 31 when the total byte code is <= 62
|
||||||
|
bitArray.appendBits(31, 5); // BINARY_SHIFT
|
||||||
|
if (bsbc > 62) {
|
||||||
|
bitArray.appendBits(bsbc as u32 - 31, 16);
|
||||||
|
} else if (i == 0) {
|
||||||
|
// 1 <= binaryShiftByteCode <= 62
|
||||||
|
bitArray.appendBits(bsbc.min( 31) as u32, 5);
|
||||||
|
} else {
|
||||||
|
// 32 <= binaryShiftCount <= 62 and i == 31
|
||||||
|
bitArray.appendBits(bsbc as u32 - 31, 5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bitArray.appendBits(text[self.binaryShiftStart as usize + i].into(), 8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Override
|
||||||
|
// public String toString() {
|
||||||
|
// return "<" + binaryShiftStart + "::" + (binaryShiftStart + binaryShiftByteCount - 1) + '>';
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for BinaryShiftToken {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"<{}::{}>",
|
||||||
|
self.binaryShiftStart,
|
||||||
|
(self.binaryShiftStart + self.binaryShiftByteCount - 1)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -14,20 +14,9 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.google.zxing.aztec.encoder;
|
use crate::common::BitArray;
|
||||||
|
|
||||||
import com.google.zxing.common.BitArray;
|
|
||||||
import com.google.zxing.common.CharacterSetECI;
|
|
||||||
|
|
||||||
import java.nio.charset.Charset;
|
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Comparator;
|
|
||||||
import java.util.Deque;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.LinkedList;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This produces nearly optimal encodings of text into the first-level of
|
* This produces nearly optimal encodings of text into the first-level of
|
||||||
@@ -41,133 +30,191 @@ import java.util.LinkedList;
|
|||||||
* @author Frank Yellin
|
* @author Frank Yellin
|
||||||
* @author Rustam Abdullaev
|
* @author Rustam Abdullaev
|
||||||
*/
|
*/
|
||||||
public final class HighLevelEncoder {
|
pub struct HighLevelEncoder {
|
||||||
|
|
||||||
static final String[] MODE_NAMES = {"UPPER", "LOWER", "DIGIT", "MIXED", "PUNCT"};
|
text:Vec<u8>,
|
||||||
|
charset: &'static dyn encoding::Encoding,
|
||||||
|
|
||||||
static final int MODE_UPPER = 0; // 5 bits
|
}
|
||||||
static final int MODE_LOWER = 1; // 5 bits
|
|
||||||
static final int MODE_DIGIT = 2; // 4 bits
|
impl HighLevelEncoder {
|
||||||
static final int MODE_MIXED = 3; // 5 bits
|
pub const MODE_NAMES : [&str] = ["UPPER", "LOWER", "DIGIT", "MIXED", "PUNCT"];
|
||||||
static final int MODE_PUNCT = 4; // 5 bits
|
|
||||||
|
const MODE_UPPER :u32= 0; // 5 bits
|
||||||
|
const MODE_LOWER :u32 = 1; // 5 bits
|
||||||
|
const MODE_DIGIT :u32 = 2; // 4 bits
|
||||||
|
const MODE_MIXED :u32 = 3; // 5 bits
|
||||||
|
const MODE_PUNCT :u32 = 4; // 5 bits
|
||||||
|
|
||||||
// The Latch Table shows, for each pair of Modes, the optimal method for
|
// The Latch Table shows, for each pair of Modes, the optimal method for
|
||||||
// getting from one mode to another. In the worst possible case, this can
|
// getting from one mode to another. In the worst possible case, this can
|
||||||
// be up to 14 bits. In the best possible case, we are already there!
|
// be up to 14 bits. In the best possible case, we are already there!
|
||||||
// The high half-word of each entry gives the number of bits.
|
// The high half-word of each entry gives the number of bits.
|
||||||
// The low half-word of each entry are the actual bits necessary to change
|
// The low half-word of each entry are the actual bits necessary to change
|
||||||
static final int[][] LATCH_TABLE = {
|
const LATCH_TABLE : [[u32]]= [
|
||||||
{
|
[
|
||||||
0,
|
0,
|
||||||
(5 << 16) + 28, // UPPER -> LOWER
|
(5 << 16) + 28, // UPPER -> LOWER
|
||||||
(5 << 16) + 30, // UPPER -> DIGIT
|
(5 << 16) + 30, // UPPER -> DIGIT
|
||||||
(5 << 16) + 29, // UPPER -> MIXED
|
(5 << 16) + 29, // UPPER -> MIXED
|
||||||
(10 << 16) + (29 << 5) + 30, // UPPER -> MIXED -> PUNCT
|
(10 << 16) + (29 << 5) + 30, // UPPER -> MIXED -> PUNCT
|
||||||
},
|
],
|
||||||
{
|
[
|
||||||
(9 << 16) + (30 << 4) + 14, // LOWER -> DIGIT -> UPPER
|
(9 << 16) + (30 << 4) + 14, // LOWER -> DIGIT -> UPPER
|
||||||
0,
|
0,
|
||||||
(5 << 16) + 30, // LOWER -> DIGIT
|
(5 << 16) + 30, // LOWER -> DIGIT
|
||||||
(5 << 16) + 29, // LOWER -> MIXED
|
(5 << 16) + 29, // LOWER -> MIXED
|
||||||
(10 << 16) + (29 << 5) + 30, // LOWER -> MIXED -> PUNCT
|
(10 << 16) + (29 << 5) + 30, // LOWER -> MIXED -> PUNCT
|
||||||
},
|
],
|
||||||
{
|
[
|
||||||
(4 << 16) + 14, // DIGIT -> UPPER
|
(4 << 16) + 14, // DIGIT -> UPPER
|
||||||
(9 << 16) + (14 << 5) + 28, // DIGIT -> UPPER -> LOWER
|
(9 << 16) + (14 << 5) + 28, // DIGIT -> UPPER -> LOWER
|
||||||
0,
|
0,
|
||||||
(9 << 16) + (14 << 5) + 29, // DIGIT -> UPPER -> MIXED
|
(9 << 16) + (14 << 5) + 29, // DIGIT -> UPPER -> MIXED
|
||||||
(14 << 16) + (14 << 10) + (29 << 5) + 30,
|
(14 << 16) + (14 << 10) + (29 << 5) + 30,
|
||||||
// DIGIT -> UPPER -> MIXED -> PUNCT
|
] // DIGIT -> UPPER -> MIXED -> PUNCT
|
||||||
},
|
,
|
||||||
{
|
[
|
||||||
(5 << 16) + 29, // MIXED -> UPPER
|
(5 << 16) + 29, // MIXED -> UPPER
|
||||||
(5 << 16) + 28, // MIXED -> LOWER
|
(5 << 16) + 28, // MIXED -> LOWER
|
||||||
(10 << 16) + (29 << 5) + 30, // MIXED -> UPPER -> DIGIT
|
(10 << 16) + (29 << 5) + 30, // MIXED -> UPPER -> DIGIT
|
||||||
0,
|
0,
|
||||||
(5 << 16) + 30, // MIXED -> PUNCT
|
(5 << 16) + 30, // MIXED -> PUNCT
|
||||||
},
|
],
|
||||||
{
|
[
|
||||||
(5 << 16) + 31, // PUNCT -> UPPER
|
(5 << 16) + 31, // PUNCT -> UPPER
|
||||||
(10 << 16) + (31 << 5) + 28, // PUNCT -> UPPER -> LOWER
|
(10 << 16) + (31 << 5) + 28, // PUNCT -> UPPER -> LOWER
|
||||||
(10 << 16) + (31 << 5) + 30, // PUNCT -> UPPER -> DIGIT
|
(10 << 16) + (31 << 5) + 30, // PUNCT -> UPPER -> DIGIT
|
||||||
(10 << 16) + (31 << 5) + 29, // PUNCT -> UPPER -> MIXED
|
(10 << 16) + (31 << 5) + 29, // PUNCT -> UPPER -> MIXED
|
||||||
0,
|
0,
|
||||||
},
|
],
|
||||||
};
|
];
|
||||||
|
|
||||||
// A reverse mapping from [mode][char] to the encoding for that character
|
// A reverse mapping from [mode][char] to the encoding for that character
|
||||||
// in that mode. An entry of 0 indicates no mapping exists.
|
// in that mode. An entry of 0 indicates no mapping exists.
|
||||||
private static final int[][] CHAR_MAP = new int[5][256];
|
const CHAR_MAP : [[u32]] = {
|
||||||
static {
|
let char_map = vec![vec![0u32;256];5];
|
||||||
CHAR_MAP[MODE_UPPER][' '] = 1;
|
char_map[Self::MODE_UPPER][' '] = 1;
|
||||||
for (int c = 'A'; c <= 'Z'; c++) {
|
for (int c = 'A'; c <= 'Z'; c++) {
|
||||||
CHAR_MAP[MODE_UPPER][c] = c - 'A' + 2;
|
char_map[Self::MODE_UPPER][c] = c - 'A' + 2;
|
||||||
}
|
}
|
||||||
CHAR_MAP[MODE_LOWER][' '] = 1;
|
char_map[Self::MODE_LOWER][' '] = 1;
|
||||||
for (int c = 'a'; c <= 'z'; c++) {
|
for (int c = 'a'; c <= 'z'; c++) {
|
||||||
CHAR_MAP[MODE_LOWER][c] = c - 'a' + 2;
|
char_map[Self::MODE_LOWER][c] = c - 'a' + 2;
|
||||||
}
|
}
|
||||||
CHAR_MAP[MODE_DIGIT][' '] = 1;
|
char_map[Self::MODE_DIGIT][' '] = 1;
|
||||||
for (int c = '0'; c <= '9'; c++) {
|
for (int c = '0'; c <= '9'; c++) {
|
||||||
CHAR_MAP[MODE_DIGIT][c] = c - '0' + 2;
|
char_map[Self::MODE_DIGIT][c] = c - '0' + 2;
|
||||||
}
|
}
|
||||||
CHAR_MAP[MODE_DIGIT][','] = 12;
|
char_map[Self::MODE_DIGIT][','] = 12;
|
||||||
CHAR_MAP[MODE_DIGIT]['.'] = 13;
|
char_map[Self::MODE_DIGIT]['.'] = 13;
|
||||||
int[] mixedTable = {
|
let mixedTable = [
|
||||||
'\0', ' ', '\1', '\2', '\3', '\4', '\5', '\6', '\7', '\b', '\t', '\n',
|
'\0', ' ', '\1', '\2', '\3', '\4', '\5', '\6', '\7', '\b', '\t', '\n',
|
||||||
'\13', '\f', '\r', '\33', '\34', '\35', '\36', '\37', '@', '\\', '^',
|
'\13', '\f', '\r', '\33', '\34', '\35', '\36', '\37', '@', '\\', '^',
|
||||||
'_', '`', '|', '~', '\177'
|
'_', '`', '|', '~', '\177'
|
||||||
};
|
];
|
||||||
for (int i = 0; i < mixedTable.length; i++) {
|
for (int i = 0; i < mixedTable.length; i++) {
|
||||||
CHAR_MAP[MODE_MIXED][mixedTable[i]] = i;
|
CHAR_MAP[MODE_MIXED][mixedTable[i]] = i;
|
||||||
}
|
}
|
||||||
int[] punctTable = {
|
let punctTable = [
|
||||||
'\0', '\r', '\0', '\0', '\0', '\0', '!', '\'', '#', '$', '%', '&', '\'',
|
'\0', '\r', '\0', '\0', '\0', '\0', '!', '\'', '#', '$', '%', '&', '\'',
|
||||||
'(', ')', '*', '+', ',', '-', '.', '/', ':', ';', '<', '=', '>', '?',
|
'(', ')', '*', '+', ',', '-', '.', '/', ':', ';', '<', '=', '>', '?',
|
||||||
'[', ']', '{', '}'
|
'[', ']', '{', '}'
|
||||||
};
|
];
|
||||||
for (int i = 0; i < punctTable.length; i++) {
|
for (int i = 0; i < punctTable.length; i++) {
|
||||||
if (punctTable[i] > 0) {
|
if (punctTable[i] > 0) {
|
||||||
CHAR_MAP[MODE_PUNCT][punctTable[i]] = i;
|
CHAR_MAP[MODE_PUNCT][punctTable[i]] = i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
// private static final int[][] CHAR_MAP = new int[5][256];
|
||||||
|
// static {
|
||||||
|
// CHAR_MAP[MODE_UPPER][' '] = 1;
|
||||||
|
// for (int c = 'A'; c <= 'Z'; c++) {
|
||||||
|
// CHAR_MAP[MODE_UPPER][c] = c - 'A' + 2;
|
||||||
|
// }
|
||||||
|
// CHAR_MAP[MODE_LOWER][' '] = 1;
|
||||||
|
// for (int c = 'a'; c <= 'z'; c++) {
|
||||||
|
// CHAR_MAP[MODE_LOWER][c] = c - 'a' + 2;
|
||||||
|
// }
|
||||||
|
// CHAR_MAP[MODE_DIGIT][' '] = 1;
|
||||||
|
// for (int c = '0'; c <= '9'; c++) {
|
||||||
|
// CHAR_MAP[MODE_DIGIT][c] = c - '0' + 2;
|
||||||
|
// }
|
||||||
|
// CHAR_MAP[MODE_DIGIT][','] = 12;
|
||||||
|
// CHAR_MAP[MODE_DIGIT]['.'] = 13;
|
||||||
|
// int[] mixedTable = {
|
||||||
|
// '\0', ' ', '\1', '\2', '\3', '\4', '\5', '\6', '\7', '\b', '\t', '\n',
|
||||||
|
// '\13', '\f', '\r', '\33', '\34', '\35', '\36', '\37', '@', '\\', '^',
|
||||||
|
// '_', '`', '|', '~', '\177'
|
||||||
|
// };
|
||||||
|
// for (int i = 0; i < mixedTable.length; i++) {
|
||||||
|
// CHAR_MAP[MODE_MIXED][mixedTable[i]] = i;
|
||||||
|
// }
|
||||||
|
// int[] punctTable = {
|
||||||
|
// '\0', '\r', '\0', '\0', '\0', '\0', '!', '\'', '#', '$', '%', '&', '\'',
|
||||||
|
// '(', ')', '*', '+', ',', '-', '.', '/', ':', ';', '<', '=', '>', '?',
|
||||||
|
// '[', ']', '{', '}'
|
||||||
|
// };
|
||||||
|
// for (int i = 0; i < punctTable.length; i++) {
|
||||||
|
// if (punctTable[i] > 0) {
|
||||||
|
// CHAR_MAP[MODE_PUNCT][punctTable[i]] = i;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
// A map showing the available shift codes. (The shifts to BINARY are not
|
// A map showing the available shift codes. (The shifts to BINARY are not
|
||||||
// shown
|
// shown
|
||||||
static final int[][] SHIFT_TABLE = new int[6][6]; // mode shift codes, per table
|
const SHIFT_TABLE : [[i32]]= { // mode shift codes, per table
|
||||||
static {
|
let mut shift_table = [[-1i32;6];6];
|
||||||
for (int[] table : SHIFT_TABLE) {
|
|
||||||
Arrays.fill(table, -1);
|
shift_table[Self::MODE_UPPER][Self::MODE_PUNCT] = 0;
|
||||||
|
|
||||||
|
shift_table[Self::MODE_LOWER][Self::MODE_PUNCT] = 0;
|
||||||
|
shift_table[Self::MODE_LOWER][Self::MODE_UPPER] = 28;
|
||||||
|
|
||||||
|
shift_table[Self::MODE_MIXED][Self::MODE_PUNCT] = 0;
|
||||||
|
|
||||||
|
shift_table[Self::MODE_DIGIT][Self::MODE_PUNCT] = 0;
|
||||||
|
shift_table[Self::MODE_DIGIT][Self::MODE_UPPER] = 15;
|
||||||
|
|
||||||
|
shift_table
|
||||||
|
};
|
||||||
|
// const SHIFT_TABLE : [[u32]]= new int[6][6]; // mode shift codes, per table
|
||||||
|
// static {
|
||||||
|
// for (int[] table : SHIFT_TABLE) {
|
||||||
|
// Arrays.fill(table, -1);
|
||||||
|
// }
|
||||||
|
// SHIFT_TABLE[MODE_UPPER][MODE_PUNCT] = 0;
|
||||||
|
|
||||||
|
// SHIFT_TABLE[MODE_LOWER][MODE_PUNCT] = 0;
|
||||||
|
// SHIFT_TABLE[MODE_LOWER][MODE_UPPER] = 28;
|
||||||
|
|
||||||
|
// SHIFT_TABLE[MODE_MIXED][MODE_PUNCT] = 0;
|
||||||
|
|
||||||
|
// SHIFT_TABLE[MODE_DIGIT][MODE_PUNCT] = 0;
|
||||||
|
// SHIFT_TABLE[MODE_DIGIT][MODE_UPPER] = 15;
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
pub fn new(text:Vec<u8>) -> Self{
|
||||||
|
Self{
|
||||||
|
text,
|
||||||
|
charset: encoding::all::UTF_8,
|
||||||
}
|
}
|
||||||
SHIFT_TABLE[MODE_UPPER][MODE_PUNCT] = 0;
|
|
||||||
|
|
||||||
SHIFT_TABLE[MODE_LOWER][MODE_PUNCT] = 0;
|
|
||||||
SHIFT_TABLE[MODE_LOWER][MODE_UPPER] = 28;
|
|
||||||
|
|
||||||
SHIFT_TABLE[MODE_MIXED][MODE_PUNCT] = 0;
|
|
||||||
|
|
||||||
SHIFT_TABLE[MODE_DIGIT][MODE_PUNCT] = 0;
|
|
||||||
SHIFT_TABLE[MODE_DIGIT][MODE_UPPER] = 15;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private final byte[] text;
|
pub fn with_charset(text:Vec<u8>, charset:&'static dyn encoding::Encoding) -> Self{
|
||||||
private final Charset charset;
|
Self{
|
||||||
|
text,
|
||||||
public HighLevelEncoder(byte[] text) {
|
charset,
|
||||||
this.text = text;
|
|
||||||
this.charset = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public HighLevelEncoder(byte[] text, Charset charset) {
|
|
||||||
this.text = text;
|
|
||||||
this.charset = charset;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return text represented by this encoder encoded as a {@link BitArray}
|
* @return text represented by this encoder encoded as a {@link BitArray}
|
||||||
*/
|
*/
|
||||||
public BitArray encode() {
|
pub fn encode(&self)-> BitArray {
|
||||||
State initialState = State.INITIAL_STATE;
|
State initialState = State.INITIAL_STATE;
|
||||||
if (charset != null) {
|
if (charset != null) {
|
||||||
CharacterSetECI eci = CharacterSetECI.getCharacterSetECI(charset);
|
CharacterSetECI eci = CharacterSetECI.getCharacterSetECI(charset);
|
||||||
13
src/aztec/encoder/mod.rs
Normal file
13
src/aztec/encoder/mod.rs
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
mod aztec_code;
|
||||||
|
mod token;
|
||||||
|
mod simple_token;
|
||||||
|
mod binary_shift_token;
|
||||||
|
mod state;
|
||||||
|
mod high_level_encoder;
|
||||||
|
|
||||||
|
pub use aztec_code::*;
|
||||||
|
pub use token::*;
|
||||||
|
pub use simple_token::*;
|
||||||
|
pub use binary_shift_token::*;
|
||||||
|
pub use state::*;
|
||||||
|
pub use high_level_encoder::*;
|
||||||
54
src/aztec/encoder/simple_token.rs
Normal file
54
src/aztec/encoder/simple_token.rs
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013 ZXing authors
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
|
use crate::common::BitArray;
|
||||||
|
|
||||||
|
#[derive(Debug,PartialEq, Eq,Clone)]
|
||||||
|
pub struct SimpleToken {
|
||||||
|
// For normal words, indicates value and bitCount
|
||||||
|
value: u16,
|
||||||
|
bitCount: u16,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SimpleToken {
|
||||||
|
pub fn new(value: i32, bitCount: u32) -> Self {
|
||||||
|
Self {
|
||||||
|
value: value as u16,
|
||||||
|
bitCount: bitCount as u16,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn appendTo(&self, bitArray: &mut BitArray, text: &[u8]) {
|
||||||
|
bitArray.appendBits(self.value as u32, self.bitCount as usize).expect("append should never fail");
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Override
|
||||||
|
// public String toString() {
|
||||||
|
// int value = this.value & ((1 << bitCount) - 1);
|
||||||
|
// value |= 1 << bitCount;
|
||||||
|
// return '<' + Integer.toBinaryString(value | (1 << bitCount)).substring(1) + '>';
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for SimpleToken {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
let mut value = self.value & ((1 << self.bitCount) - 1);
|
||||||
|
value |= 1 << self.bitCount;
|
||||||
|
write!(f, "<{:#016b}>", value | (1 << self.bitCount))
|
||||||
|
}
|
||||||
|
}
|
||||||
212
src/aztec/encoder/state.rs
Normal file
212
src/aztec/encoder/state.rs
Normal file
@@ -0,0 +1,212 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013 ZXing authors
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
|
use crate::{exceptions::Exceptions, common::BitArray};
|
||||||
|
|
||||||
|
use super::{Token, TokenType};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* State represents all information about a sequence necessary to generate the current output.
|
||||||
|
* Note that a state is immutable.
|
||||||
|
*/
|
||||||
|
pub struct State {
|
||||||
|
|
||||||
|
// static final State INITIAL_STATE = new State(Token.EMPTY, HighLevelEncoder.MODE_UPPER, 0, 0);
|
||||||
|
|
||||||
|
// The current mode of the encoding (or the mode to which we'll return if
|
||||||
|
// we're in Binary Shift mode.
|
||||||
|
mode:u32,
|
||||||
|
// The list of tokens that we output. If we are in Binary Shift mode, this
|
||||||
|
// token list does *not* yet included the token for those bytes
|
||||||
|
token:Token,
|
||||||
|
// If non-zero, the number of most recent bytes that should be output
|
||||||
|
// in Binary Shift mode.
|
||||||
|
binaryShiftByteCount:u32,
|
||||||
|
// The total number of bits generated (including Binary Shift).
|
||||||
|
bitCount:u32,
|
||||||
|
binaryShiftCost:u32,
|
||||||
|
}
|
||||||
|
impl State {
|
||||||
|
pub fn new( token:Token, mode:u32, binaryBytes:u32, bitCount:u32) -> Self{
|
||||||
|
Self{
|
||||||
|
mode,
|
||||||
|
token,
|
||||||
|
binaryShiftByteCount: binaryBytes,
|
||||||
|
bitCount,
|
||||||
|
binaryShiftCost: Self::calculateBinaryShiftCost(binaryBytes),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn getMode(&self) -> u32{
|
||||||
|
self.mode
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn getToken(&self) -> &Token{
|
||||||
|
&self.token
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn getBinaryShiftByteCount(&self) -> u32{
|
||||||
|
self.binaryShiftByteCount
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn getBitCount(&self) -> u32{
|
||||||
|
self.bitCount
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn appendFLGn(&self, eci:u32) -> Result<Self,Exceptions> {
|
||||||
|
let result = self.shiftAndAppend(HighLevelEncoder::MODE_PUNCT, 0); // 0: FLG(n)
|
||||||
|
let token = result.token;
|
||||||
|
let bitsAdded = 3;
|
||||||
|
if eci < 0 {
|
||||||
|
token.add(0, 3); // 0: FNC1
|
||||||
|
} else if eci > 999999 {
|
||||||
|
return Err(Exceptions::IllegalArgumentException("ECI code must be between 0 and 999999".to_owned()));
|
||||||
|
// throw new IllegalArgumentException("ECI code must be between 0 and 999999");
|
||||||
|
} else {
|
||||||
|
let eciDigits = Integer.toString(eci).getBytes(StandardCharsets.ISO_8859_1);
|
||||||
|
token.add(eciDigits.length, 3); // 1-6: number of ECI digits
|
||||||
|
for eciDigit in eciDigits {
|
||||||
|
// for (byte eciDigit : eciDigits) {
|
||||||
|
token.add(eciDigit - '0' + 2, 4);
|
||||||
|
}
|
||||||
|
bitsAdded += eciDigits.length * 4;
|
||||||
|
}
|
||||||
|
Ok(State::new(token, self.mode, 0, self.bitCount + bitsAdded))
|
||||||
|
// return new State(token, mode, 0, bitCount + bitsAdded);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a new state representing this state with a latch to a (not
|
||||||
|
// necessary different) mode, and then a code.
|
||||||
|
pub fn latchAndAppend(&self, mode:u32, value:u32) -> State{
|
||||||
|
let bitCount = self.bitCount;
|
||||||
|
let token = self.token;
|
||||||
|
if mode != self.mode {
|
||||||
|
let latch = HighLevelEncoder.LATCH_TABLE[this.mode][mode];
|
||||||
|
token.add(latch & 0xFFFF, latch >> 16);
|
||||||
|
bitCount += latch >> 16;
|
||||||
|
}
|
||||||
|
let latchModeBitCount = mode == HighLevelEncoder.MODE_DIGIT ? 4 : 5;
|
||||||
|
token.add(value, latchModeBitCount);
|
||||||
|
|
||||||
|
State::new(token, mode, 0, bitCount + latchModeBitCount)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a new state representing this state, with a temporary shift
|
||||||
|
// to a different mode to output a single value.
|
||||||
|
pub fn shiftAndAppend(&self, mode:u32, value:u32) -> State{
|
||||||
|
let token = this.token;
|
||||||
|
let thisModeBitCount = this.mode == HighLevelEncoder.MODE_DIGIT ? 4 : 5;
|
||||||
|
// Shifts exist only to UPPER and PUNCT, both with tokens size 5.
|
||||||
|
token = token.add(HighLevelEncoder.SHIFT_TABLE[this.mode][mode], thisModeBitCount);
|
||||||
|
token = token.add(value, 5);
|
||||||
|
State::new(token, this.mode, 0, this.bitCount + thisModeBitCount + 5)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a new state representing this state, but an additional character
|
||||||
|
// output in Binary Shift mode.
|
||||||
|
pub fn addBinaryShiftChar(&self, index:u32) -> State{
|
||||||
|
let token = this.token;
|
||||||
|
let mode = this.mode;
|
||||||
|
let bitCount = this.bitCount;
|
||||||
|
if self.mode == HighLevelEncoder.MODE_PUNCT || self.mode == HighLevelEncoder.MODE_DIGIT {
|
||||||
|
let latch = HighLevelEncoder.LATCH_TABLE[mode][HighLevelEncoder.MODE_UPPER];
|
||||||
|
token.add(latch & 0xFFFF, latch >> 16);
|
||||||
|
bitCount += latch >> 16;
|
||||||
|
mode = HighLevelEncoder.MODE_UPPER;
|
||||||
|
}
|
||||||
|
let deltaBitCount =
|
||||||
|
(binaryShiftByteCount == 0 || binaryShiftByteCount == 31) ? 18 :
|
||||||
|
(binaryShiftByteCount == 62) ? 9 : 8;
|
||||||
|
let result = State::new(token, mode, binaryShiftByteCount + 1, bitCount + deltaBitCount);
|
||||||
|
if (result.binaryShiftByteCount == 2047 + 31) {
|
||||||
|
// The string is as long as it's allowed to be. We should end it.
|
||||||
|
result = result.endBinaryShift(index + 1);
|
||||||
|
}
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the state identical to this one, but we are no longer in
|
||||||
|
// Binary Shift mode.
|
||||||
|
pub fn endBinaryShift(self, index:u32) -> State{
|
||||||
|
if self.binaryShiftByteCount == 0 {
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
let token = self.token;
|
||||||
|
self.token.addBinaryShift(index - self.binaryShiftByteCount, self.binaryShiftByteCount);
|
||||||
|
|
||||||
|
State::new(token, self.mode, 0, self.bitCount)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns true if "this" state is better (or equal) to be in than "that"
|
||||||
|
// state under all possible circumstances.
|
||||||
|
pub fn isBetterThanOrEqualTo(&self, other:&State)->bool {
|
||||||
|
let newModeBitCount = self.bitCount + (HighLevelEncoder.LATCH_TABLE[this.mode][other.mode] >> 16);
|
||||||
|
if self.binaryShiftByteCount < other.binaryShiftByteCount {
|
||||||
|
// add additional B/S encoding cost of other, if any
|
||||||
|
newModeBitCount += other.binaryShiftCost - self.binaryShiftCost;
|
||||||
|
} else if self.binaryShiftByteCount > other.binaryShiftByteCount && other.binaryShiftByteCount > 0 {
|
||||||
|
// maximum possible additional cost (we end up exceeding the 31 byte boundary and other state can stay beneath it)
|
||||||
|
newModeBitCount += 10;
|
||||||
|
}
|
||||||
|
newModeBitCount <= other.bitCount
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn toBitArray(&self, text:&[u8]) -> BitArray{
|
||||||
|
let symbols = Vec::new();
|
||||||
|
let mut tok = self.endBinaryShift(text.len() as u32).token;
|
||||||
|
let mut tkn = tok.getPrevious();
|
||||||
|
while tkn != &TokenType::Empty {
|
||||||
|
// for (Token token = endBinaryShift(text.length).token; token != null; token = token.getPrevious()) {
|
||||||
|
symbols.push(tkn);
|
||||||
|
tkn = tok.getPrevious();
|
||||||
|
}
|
||||||
|
let bitArray = BitArray::new();
|
||||||
|
// Add each token to the result in forward order
|
||||||
|
for i in (0..symbols.len()-1).rev() {
|
||||||
|
// for (int i = symbols.size() - 1; i >= 0; i--) {
|
||||||
|
symbols.get(i).unwrap().appendTo(bitArray, text);
|
||||||
|
}
|
||||||
|
bitArray
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Override
|
||||||
|
// public String toString() {
|
||||||
|
// return String.format("%s bits=%d bytes=%d", HighLevelEncoder.MODE_NAMES[mode], bitCount, binaryShiftByteCount);
|
||||||
|
// }
|
||||||
|
|
||||||
|
fn calculateBinaryShiftCost( binaryShiftByteCount:u32) -> u32{
|
||||||
|
if binaryShiftByteCount > 62 {
|
||||||
|
return 21; // B/S with extended length
|
||||||
|
}
|
||||||
|
if binaryShiftByteCount > 31 {
|
||||||
|
return 20; // two B/S
|
||||||
|
}
|
||||||
|
if binaryShiftByteCount > 0 {
|
||||||
|
return 10; // one B/S
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for State {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(f,"{} bits={} bytes={}", HighLevelEncoder::MODE_NAMES[mode], self.bitCount, self.binaryShiftByteCount)
|
||||||
|
}
|
||||||
|
}
|
||||||
75
src/aztec/encoder/token.rs
Normal file
75
src/aztec/encoder/token.rs
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013 ZXing authors
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
use crate::common::BitArray;
|
||||||
|
|
||||||
|
use super::{SimpleToken, BinaryShiftToken};
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq, Clone)]
|
||||||
|
pub enum TokenType {
|
||||||
|
Simple(SimpleToken), BinaryShift(BinaryShiftToken), Empty
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Token {
|
||||||
|
tokens: Vec<TokenType>,
|
||||||
|
current_pointer: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Token {
|
||||||
|
pub fn new () -> Self {
|
||||||
|
Self {
|
||||||
|
tokens: vec![TokenType::Empty],
|
||||||
|
current_pointer: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn getPrevious(&mut self) -> &TokenType{
|
||||||
|
self.current_pointer -= 1;
|
||||||
|
&self.tokens[self.current_pointer]
|
||||||
|
}
|
||||||
|
pub fn add(&mut self, value:i32, bit_count: u32,) -> &TokenType {
|
||||||
|
self.current_pointer+=1;
|
||||||
|
self.tokens.push(TokenType::Simple(SimpleToken::new(value,bit_count)));
|
||||||
|
&self.tokens[self.current_pointer]
|
||||||
|
}
|
||||||
|
pub fn addBinaryShift(&mut self, start: u32, byte_count: u32) -> &TokenType {
|
||||||
|
self.current_pointer+=1;
|
||||||
|
self.tokens.push(TokenType::BinaryShift(BinaryShiftToken::new(start,byte_count)));
|
||||||
|
&self.tokens[self.current_pointer]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// pub enum Token{
|
||||||
|
// Simple(Rc<SimpleToken>),
|
||||||
|
// BinaryShift(),
|
||||||
|
// Empty,
|
||||||
|
// }
|
||||||
|
|
||||||
|
// pub trait TokenTrait {
|
||||||
|
// fn getPrevious(&self)->&Token;
|
||||||
|
|
||||||
|
// fn add(&self, value: i32, bitCount: u32) -> Token{
|
||||||
|
// Token::Simple(Rc::new(SimpleToken::new(self, value, bitCount)))
|
||||||
|
// }
|
||||||
|
|
||||||
|
// fn addBinaryShift(&self, start: i32, byteCount: u32) -> &Token; //{
|
||||||
|
// // //int bitCount = (byteCount * 8) + (byteCount <= 31 ? 10 : byteCount <= 62 ? 20 : 21);
|
||||||
|
// // return new BinaryShiftToken(this, start, byteCount);
|
||||||
|
// // }
|
||||||
|
|
||||||
|
// fn appendTo(&self, bitArray: BitArray, text: &[u8]);
|
||||||
|
// }
|
||||||
@@ -1,12 +1,13 @@
|
|||||||
mod AztecDetectorResult;
|
mod AztecDetectorResult;
|
||||||
pub mod decoder;
|
pub mod decoder;
|
||||||
pub mod detector;
|
pub mod detector;
|
||||||
|
pub mod encoder;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod DecoderTest;
|
mod DecoderTest;
|
||||||
// #[cfg(test)]
|
// #[cfg(test)]
|
||||||
// mod EncoderTest;
|
// mod EncoderTest;
|
||||||
#[cfg(test)]
|
// #[cfg(test)]
|
||||||
mod DetectorTest;
|
// mod DetectorTest;
|
||||||
|
|
||||||
mod shared_test_methods;
|
mod shared_test_methods;
|
||||||
Reference in New Issue
Block a user