mirror of
https://github.com/starovoid/rxing.git
synced 2026-07-26 20:32:34 +00:00
progress on aztec
This commit is contained in:
@@ -56,17 +56,17 @@ use crate::common::BitMatrix;
|
||||
|
||||
#[test]
|
||||
fn testErrorInParameterLocatorNotCompact() {
|
||||
String alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYabcdefghijklmnopqrstuvwxyz";
|
||||
testErrorInParameterLocator(alphabet + alphabet + alphabet);
|
||||
let alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYabcdefghijklmnopqrstuvwxyz";
|
||||
testErrorInParameterLocator(&format!("{}{}{}",alphabet , alphabet , alphabet));
|
||||
}
|
||||
|
||||
// Test that we can tolerate errors in the parameter locator bits
|
||||
fn testErrorInParameterLocator( data:&str) {
|
||||
AztecCode aztec = Encoder.encode(data, 25, Encoder.DEFAULT_AZTEC_LAYERS);
|
||||
Random random = new Random(aztec.getMatrix().hashCode()); // pseudo-random, but deterministic
|
||||
int layers = aztec.getLayers();
|
||||
boolean compact = aztec.isCompact();
|
||||
List<Point> orientationPoints = getOrientationPoints(aztec);
|
||||
let aztec = Encoder.encode(data, 25, Encoder.DEFAULT_AZTEC_LAYERS);
|
||||
let random = new Random(aztec.getMatrix().hashCode()); // pseudo-random, but deterministic
|
||||
let layers = aztec.getLayers();
|
||||
let compact = aztec.isCompact();
|
||||
let orientationPoints = getOrientationPoints(aztec);
|
||||
for (boolean isMirror : new boolean[] { false, true }) {
|
||||
for (BitMatrix matrix : getRotations(aztec.getMatrix())) {
|
||||
// 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.
|
||||
fn getRotations( matrix0:&BitMatrix)-> Vec<BitMatrix> {
|
||||
BitMatrix matrix90 = rotateRight(matrix0);
|
||||
BitMatrix matrix180 = rotateRight(matrix90);
|
||||
BitMatrix matrix270 = rotateRight(matrix180);
|
||||
let matrix90 = rotateRight(matrix0);
|
||||
let matrix180 = rotateRight(matrix90);
|
||||
let matrix270 = rotateRight(matrix180);
|
||||
return Arrays.asList(matrix0, matrix90, matrix180, matrix270);
|
||||
}
|
||||
|
||||
// Rotates a square BitMatrix to the right by 90 degrees
|
||||
fn rotateRight( input:&BitMatrix) -> BitMatrix{
|
||||
int width = input.getWidth();
|
||||
BitMatrix result = new BitMatrix(width);
|
||||
let width = input.getWidth();
|
||||
let result = new BitMatrix(width);
|
||||
for (int x = 0; x < width; x++) {
|
||||
for (int y = 0; y < width; 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
|
||||
fn transpose( input:&BitMatrix) -> BitMatrix {
|
||||
let width = input.getWidth();
|
||||
BitMatrix result = new BitMatrix(width);
|
||||
let result = new BitMatrix(width);
|
||||
for (int x = 0; x < width; x++) {
|
||||
for (int y = 0; y < width; y++) {
|
||||
if (input.get(x, y)) {
|
||||
@@ -161,8 +161,8 @@ use crate::common::BitMatrix;
|
||||
}
|
||||
|
||||
fn clone( input:&BitMatrix) -> BitMatrix {
|
||||
int width = input.getWidth();
|
||||
BitMatrix result = new BitMatrix(width);
|
||||
let width = input.getWidth();
|
||||
let result = new BitMatrix(width);
|
||||
for (int x = 0; x < width; x++) {
|
||||
for (int y = 0; y < width; y++) {
|
||||
if (input.get(x,y)) {
|
||||
@@ -173,10 +173,10 @@ use crate::common::BitMatrix;
|
||||
return result;
|
||||
}
|
||||
|
||||
fn getOrientationPoints( code::&AztecCode) -> Vec<Point> {
|
||||
int center = code.getMatrix().getWidth() / 2;
|
||||
int offset = code.isCompact() ? 5 : 7;
|
||||
List<Point> result = new ArrayList<>();
|
||||
fn getOrientationPoints( code:&AztecCode) -> Vec<Point> {
|
||||
let center = code.getMatrix().getWidth() / 2;
|
||||
let offset = code.isCompact() ? 5 : 7;
|
||||
let result = new ArrayList<>();
|
||||
for (int xSign = -1; xSign <= 1; xSign += 2) {
|
||||
for (int ySign = -1; ySign <= 1; ySign += 2) {
|
||||
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.
|
||||
*/
|
||||
|
||||
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
|
||||
@@ -41,133 +30,191 @@ import java.util.LinkedList;
|
||||
* @author Frank Yellin
|
||||
* @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
|
||||
static final int MODE_MIXED = 3; // 5 bits
|
||||
static final int MODE_PUNCT = 4; // 5 bits
|
||||
}
|
||||
|
||||
impl HighLevelEncoder {
|
||||
pub const MODE_NAMES : [&str] = ["UPPER", "LOWER", "DIGIT", "MIXED", "PUNCT"];
|
||||
|
||||
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
|
||||
// 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!
|
||||
// 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
|
||||
static final int[][] LATCH_TABLE = {
|
||||
{
|
||||
const LATCH_TABLE : [[u32]]= [
|
||||
[
|
||||
0,
|
||||
(5 << 16) + 28, // UPPER -> LOWER
|
||||
(5 << 16) + 30, // UPPER -> DIGIT
|
||||
(5 << 16) + 29, // UPPER -> MIXED
|
||||
(10 << 16) + (29 << 5) + 30, // UPPER -> MIXED -> PUNCT
|
||||
},
|
||||
{
|
||||
],
|
||||
[
|
||||
(9 << 16) + (30 << 4) + 14, // LOWER -> DIGIT -> UPPER
|
||||
0,
|
||||
(5 << 16) + 30, // LOWER -> DIGIT
|
||||
(5 << 16) + 29, // LOWER -> MIXED
|
||||
(10 << 16) + (29 << 5) + 30, // LOWER -> MIXED -> PUNCT
|
||||
},
|
||||
{
|
||||
],
|
||||
[
|
||||
(4 << 16) + 14, // DIGIT -> UPPER
|
||||
(9 << 16) + (14 << 5) + 28, // DIGIT -> UPPER -> LOWER
|
||||
0,
|
||||
(9 << 16) + (14 << 5) + 29, // DIGIT -> UPPER -> MIXED
|
||||
(14 << 16) + (14 << 10) + (29 << 5) + 30,
|
||||
// DIGIT -> UPPER -> MIXED -> PUNCT
|
||||
},
|
||||
{
|
||||
] // DIGIT -> UPPER -> MIXED -> PUNCT
|
||||
,
|
||||
[
|
||||
(5 << 16) + 29, // MIXED -> UPPER
|
||||
(5 << 16) + 28, // MIXED -> LOWER
|
||||
(10 << 16) + (29 << 5) + 30, // MIXED -> UPPER -> DIGIT
|
||||
0,
|
||||
(5 << 16) + 30, // MIXED -> PUNCT
|
||||
},
|
||||
{
|
||||
],
|
||||
[
|
||||
(5 << 16) + 31, // PUNCT -> UPPER
|
||||
(10 << 16) + (31 << 5) + 28, // PUNCT -> UPPER -> LOWER
|
||||
(10 << 16) + (31 << 5) + 30, // PUNCT -> UPPER -> DIGIT
|
||||
(10 << 16) + (31 << 5) + 29, // PUNCT -> UPPER -> MIXED
|
||||
0,
|
||||
},
|
||||
};
|
||||
],
|
||||
];
|
||||
|
||||
// A reverse mapping from [mode][char] to the encoding for that character
|
||||
// in that mode. An entry of 0 indicates no mapping exists.
|
||||
private static final int[][] CHAR_MAP = new int[5][256];
|
||||
static {
|
||||
CHAR_MAP[MODE_UPPER][' '] = 1;
|
||||
const CHAR_MAP : [[u32]] = {
|
||||
let char_map = vec![vec![0u32;256];5];
|
||||
char_map[Self::MODE_UPPER][' '] = 1;
|
||||
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++) {
|
||||
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++) {
|
||||
CHAR_MAP[MODE_DIGIT][c] = c - '0' + 2;
|
||||
char_map[Self::MODE_DIGIT][c] = c - '0' + 2;
|
||||
}
|
||||
CHAR_MAP[MODE_DIGIT][','] = 12;
|
||||
CHAR_MAP[MODE_DIGIT]['.'] = 13;
|
||||
int[] mixedTable = {
|
||||
char_map[Self::MODE_DIGIT][','] = 12;
|
||||
char_map[Self::MODE_DIGIT]['.'] = 13;
|
||||
let 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 = {
|
||||
let 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
// 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
|
||||
// shown
|
||||
static final int[][] SHIFT_TABLE = new int[6][6]; // mode shift codes, per table
|
||||
static {
|
||||
for (int[] table : SHIFT_TABLE) {
|
||||
Arrays.fill(table, -1);
|
||||
const SHIFT_TABLE : [[i32]]= { // mode shift codes, per table
|
||||
let mut shift_table = [[-1i32;6];6];
|
||||
|
||||
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;
|
||||
private final Charset charset;
|
||||
|
||||
public HighLevelEncoder(byte[] text) {
|
||||
this.text = text;
|
||||
this.charset = null;
|
||||
}
|
||||
|
||||
public HighLevelEncoder(byte[] text, Charset charset) {
|
||||
this.text = text;
|
||||
this.charset = charset;
|
||||
pub fn with_charset(text:Vec<u8>, charset:&'static dyn encoding::Encoding) -> Self{
|
||||
Self{
|
||||
text,
|
||||
charset,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return text represented by this encoder encoded as a {@link BitArray}
|
||||
*/
|
||||
public BitArray encode() {
|
||||
pub fn encode(&self)-> BitArray {
|
||||
State initialState = State.INITIAL_STATE;
|
||||
if (charset != null) {
|
||||
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;
|
||||
pub mod decoder;
|
||||
pub mod detector;
|
||||
pub mod encoder;
|
||||
|
||||
#[cfg(test)]
|
||||
mod DecoderTest;
|
||||
// #[cfg(test)]
|
||||
// mod EncoderTest;
|
||||
#[cfg(test)]
|
||||
mod DetectorTest;
|
||||
// #[cfg(test)]
|
||||
// mod DetectorTest;
|
||||
|
||||
mod shared_test_methods;
|
||||
Reference in New Issue
Block a user