port encoder context and associated

This commit is contained in:
Henry Schimke
2022-10-26 11:04:35 -05:00
parent edf2b46b78
commit 55f95540f9
10 changed files with 698 additions and 530 deletions

View File

@@ -1,35 +0,0 @@
/*
* Copyright 2006 Jeremias Maerki
*
* 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.datamatrix.encoder;
final class DataMatrixSymbolInfo144 extends SymbolInfo {
DataMatrixSymbolInfo144() {
super(false, 1558, 620, 22, 22, 36, -1, 62);
}
@Override
public int getInterleavedBlockCount() {
return 10;
}
@Override
public int getDataLengthForInterleavedBlock(int index) {
return (index <= 8) ? 156 : 155;
}
}

View File

@@ -1,134 +0,0 @@
/*
* Copyright 2006-2007 Jeremias Maerki.
*
* 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.datamatrix.encoder;
import com.google.zxing.Dimension;
import java.nio.charset.StandardCharsets;
final class EncoderContext {
private final String msg;
private SymbolShapeHint shape;
private Dimension minSize;
private Dimension maxSize;
private final StringBuilder codewords;
int pos;
private int newEncoding;
private SymbolInfo symbolInfo;
private int skipAtEnd;
EncoderContext(String msg) {
//From this point on Strings are not Unicode anymore!
byte[] msgBinary = msg.getBytes(StandardCharsets.ISO_8859_1);
StringBuilder sb = new StringBuilder(msgBinary.length);
for (int i = 0, c = msgBinary.length; i < c; i++) {
char ch = (char) (msgBinary[i] & 0xff);
if (ch == '?' && msg.charAt(i) != '?') {
throw new IllegalArgumentException("Message contains characters outside ISO-8859-1 encoding.");
}
sb.append(ch);
}
this.msg = sb.toString(); //Not Unicode here!
shape = SymbolShapeHint.FORCE_NONE;
this.codewords = new StringBuilder(msg.length());
newEncoding = -1;
}
public void setSymbolShape(SymbolShapeHint shape) {
this.shape = shape;
}
public void setSizeConstraints(Dimension minSize, Dimension maxSize) {
this.minSize = minSize;
this.maxSize = maxSize;
}
public String getMessage() {
return this.msg;
}
public void setSkipAtEnd(int count) {
this.skipAtEnd = count;
}
public char getCurrentChar() {
return msg.charAt(pos);
}
public char getCurrent() {
return msg.charAt(pos);
}
public StringBuilder getCodewords() {
return codewords;
}
public void writeCodewords(String codewords) {
this.codewords.append(codewords);
}
public void writeCodeword(char codeword) {
this.codewords.append(codeword);
}
public int getCodewordCount() {
return this.codewords.length();
}
public int getNewEncoding() {
return newEncoding;
}
public void signalEncoderChange(int encoding) {
this.newEncoding = encoding;
}
public void resetEncoderSignal() {
this.newEncoding = -1;
}
public boolean hasMoreCharacters() {
return pos < getTotalMessageCharCount();
}
private int getTotalMessageCharCount() {
return msg.length() - skipAtEnd;
}
public int getRemainingCharacters() {
return getTotalMessageCharCount() - pos;
}
public SymbolInfo getSymbolInfo() {
return symbolInfo;
}
public void updateSymbolInfo() {
updateSymbolInfo(getCodewordCount());
}
public void updateSymbolInfo(int len) {
if (this.symbolInfo == null || len > this.symbolInfo.getDataCapacity()) {
this.symbolInfo = SymbolInfo.lookup(len, shape, minSize, maxSize, true);
}
}
public void resetSymbolInfo() {
this.symbolInfo = null;
}
}

View File

@@ -1,236 +0,0 @@
/*
* Copyright 2006 Jeremias Maerki
*
* 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.datamatrix.encoder;
import com.google.zxing.Dimension;
/**
* Symbol info table for DataMatrix.
*
* @version $Id$
*/
public class SymbolInfo {
static final SymbolInfo[] PROD_SYMBOLS = {
new SymbolInfo(false, 3, 5, 8, 8, 1),
new SymbolInfo(false, 5, 7, 10, 10, 1),
/*rect*/new SymbolInfo(true, 5, 7, 16, 6, 1),
new SymbolInfo(false, 8, 10, 12, 12, 1),
/*rect*/new SymbolInfo(true, 10, 11, 14, 6, 2),
new SymbolInfo(false, 12, 12, 14, 14, 1),
/*rect*/new SymbolInfo(true, 16, 14, 24, 10, 1),
new SymbolInfo(false, 18, 14, 16, 16, 1),
new SymbolInfo(false, 22, 18, 18, 18, 1),
/*rect*/new SymbolInfo(true, 22, 18, 16, 10, 2),
new SymbolInfo(false, 30, 20, 20, 20, 1),
/*rect*/new SymbolInfo(true, 32, 24, 16, 14, 2),
new SymbolInfo(false, 36, 24, 22, 22, 1),
new SymbolInfo(false, 44, 28, 24, 24, 1),
/*rect*/new SymbolInfo(true, 49, 28, 22, 14, 2),
new SymbolInfo(false, 62, 36, 14, 14, 4),
new SymbolInfo(false, 86, 42, 16, 16, 4),
new SymbolInfo(false, 114, 48, 18, 18, 4),
new SymbolInfo(false, 144, 56, 20, 20, 4),
new SymbolInfo(false, 174, 68, 22, 22, 4),
new SymbolInfo(false, 204, 84, 24, 24, 4, 102, 42),
new SymbolInfo(false, 280, 112, 14, 14, 16, 140, 56),
new SymbolInfo(false, 368, 144, 16, 16, 16, 92, 36),
new SymbolInfo(false, 456, 192, 18, 18, 16, 114, 48),
new SymbolInfo(false, 576, 224, 20, 20, 16, 144, 56),
new SymbolInfo(false, 696, 272, 22, 22, 16, 174, 68),
new SymbolInfo(false, 816, 336, 24, 24, 16, 136, 56),
new SymbolInfo(false, 1050, 408, 18, 18, 36, 175, 68),
new SymbolInfo(false, 1304, 496, 20, 20, 36, 163, 62),
new DataMatrixSymbolInfo144(),
};
private static SymbolInfo[] symbols = PROD_SYMBOLS;
private final boolean rectangular;
private final int dataCapacity;
private final int errorCodewords;
public final int matrixWidth;
public final int matrixHeight;
private final int dataRegions;
private final int rsBlockData;
private final int rsBlockError;
/**
* Overrides the symbol info set used by this class. Used for testing purposes.
*
* @param override the symbol info set to use
*/
public static void overrideSymbolSet(SymbolInfo[] override) {
symbols = override;
}
public SymbolInfo(boolean rectangular, int dataCapacity, int errorCodewords,
int matrixWidth, int matrixHeight, int dataRegions) {
this(rectangular, dataCapacity, errorCodewords, matrixWidth, matrixHeight, dataRegions,
dataCapacity, errorCodewords);
}
SymbolInfo(boolean rectangular, int dataCapacity, int errorCodewords,
int matrixWidth, int matrixHeight, int dataRegions,
int rsBlockData, int rsBlockError) {
this.rectangular = rectangular;
this.dataCapacity = dataCapacity;
this.errorCodewords = errorCodewords;
this.matrixWidth = matrixWidth;
this.matrixHeight = matrixHeight;
this.dataRegions = dataRegions;
this.rsBlockData = rsBlockData;
this.rsBlockError = rsBlockError;
}
public static SymbolInfo lookup(int dataCodewords) {
return lookup(dataCodewords, SymbolShapeHint.FORCE_NONE, true);
}
public static SymbolInfo lookup(int dataCodewords, SymbolShapeHint shape) {
return lookup(dataCodewords, shape, true);
}
public static SymbolInfo lookup(int dataCodewords, boolean allowRectangular, boolean fail) {
SymbolShapeHint shape = allowRectangular
? SymbolShapeHint.FORCE_NONE : SymbolShapeHint.FORCE_SQUARE;
return lookup(dataCodewords, shape, fail);
}
private static SymbolInfo lookup(int dataCodewords, SymbolShapeHint shape, boolean fail) {
return lookup(dataCodewords, shape, null, null, fail);
}
public static SymbolInfo lookup(int dataCodewords,
SymbolShapeHint shape,
Dimension minSize,
Dimension maxSize,
boolean fail) {
for (SymbolInfo symbol : symbols) {
if (shape == SymbolShapeHint.FORCE_SQUARE && symbol.rectangular) {
continue;
}
if (shape == SymbolShapeHint.FORCE_RECTANGLE && !symbol.rectangular) {
continue;
}
if (minSize != null
&& (symbol.getSymbolWidth() < minSize.getWidth()
|| symbol.getSymbolHeight() < minSize.getHeight())) {
continue;
}
if (maxSize != null
&& (symbol.getSymbolWidth() > maxSize.getWidth()
|| symbol.getSymbolHeight() > maxSize.getHeight())) {
continue;
}
if (dataCodewords <= symbol.dataCapacity) {
return symbol;
}
}
if (fail) {
throw new IllegalArgumentException(
"Can't find a symbol arrangement that matches the message. Data codewords: "
+ dataCodewords);
}
return null;
}
private int getHorizontalDataRegions() {
switch (dataRegions) {
case 1:
return 1;
case 2:
case 4:
return 2;
case 16:
return 4;
case 36:
return 6;
default:
throw new IllegalStateException("Cannot handle this number of data regions");
}
}
private int getVerticalDataRegions() {
switch (dataRegions) {
case 1:
case 2:
return 1;
case 4:
return 2;
case 16:
return 4;
case 36:
return 6;
default:
throw new IllegalStateException("Cannot handle this number of data regions");
}
}
public final int getSymbolDataWidth() {
return getHorizontalDataRegions() * matrixWidth;
}
public final int getSymbolDataHeight() {
return getVerticalDataRegions() * matrixHeight;
}
public final int getSymbolWidth() {
return getSymbolDataWidth() + (getHorizontalDataRegions() * 2);
}
public final int getSymbolHeight() {
return getSymbolDataHeight() + (getVerticalDataRegions() * 2);
}
public int getCodewordCount() {
return dataCapacity + errorCodewords;
}
public int getInterleavedBlockCount() {
return dataCapacity / rsBlockData;
}
public final int getDataCapacity() {
return dataCapacity;
}
public final int getErrorCodewords() {
return errorCodewords;
}
public int getDataLengthForInterleavedBlock(int index) {
return rsBlockData;
}
public final int getErrorLengthForInterleavedBlock(int index) {
return rsBlockError;
}
@Override
public final String toString() {
return (rectangular ? "Rectangular Symbol:" : "Square Symbol:") +
" data region " + matrixWidth + 'x' + matrixHeight +
", symbol size " + getSymbolWidth() + 'x' + getSymbolHeight() +
", symbol data size " + getSymbolDataWidth() + 'x' + getSymbolDataHeight() +
", codewords " + dataCapacity + '+' + errorCodewords;
}
}

View File

@@ -1,112 +0,0 @@
/*
* Copyright 2006 Jeremias Maerki
*
* 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.datamatrix.encoder;
import com.google.zxing.Dimension;
import org.junit.Assert;
import org.junit.Test;
/**
* Tests the SymbolInfo class.
*/
public final class SymbolInfoTestCase extends Assert {
@Test
public void testSymbolInfo() {
SymbolInfo info = SymbolInfo.lookup(3);
assertEquals(5, info.getErrorCodewords());
assertEquals(8, info.matrixWidth);
assertEquals(8, info.matrixHeight);
assertEquals(10, info.getSymbolWidth());
assertEquals(10, info.getSymbolHeight());
info = SymbolInfo.lookup(3, SymbolShapeHint.FORCE_RECTANGLE);
assertEquals(7, info.getErrorCodewords());
assertEquals(16, info.matrixWidth);
assertEquals(6, info.matrixHeight);
assertEquals(18, info.getSymbolWidth());
assertEquals(8, info.getSymbolHeight());
info = SymbolInfo.lookup(9);
assertEquals(11, info.getErrorCodewords());
assertEquals(14, info.matrixWidth);
assertEquals(6, info.matrixHeight);
assertEquals(32, info.getSymbolWidth());
assertEquals(8, info.getSymbolHeight());
info = SymbolInfo.lookup(9, SymbolShapeHint.FORCE_SQUARE);
assertEquals(12, info.getErrorCodewords());
assertEquals(14, info.matrixWidth);
assertEquals(14, info.matrixHeight);
assertEquals(16, info.getSymbolWidth());
assertEquals(16, info.getSymbolHeight());
try {
SymbolInfo.lookup(1559);
fail("There's no rectangular symbol for more than 1558 data codewords");
} catch (IllegalArgumentException iae) {
//expected
}
try {
SymbolInfo.lookup(50, SymbolShapeHint.FORCE_RECTANGLE);
fail("There's no rectangular symbol for 50 data codewords");
} catch (IllegalArgumentException iae) {
//expected
}
info = SymbolInfo.lookup(35);
assertEquals(24, info.getSymbolWidth());
assertEquals(24, info.getSymbolHeight());
Dimension fixedSize = new Dimension(26, 26);
info = SymbolInfo.lookup(35,
SymbolShapeHint.FORCE_NONE, fixedSize, fixedSize, false);
assertNotNull(info);
assertEquals(26, info.getSymbolWidth());
assertEquals(26, info.getSymbolHeight());
info = SymbolInfo.lookup(45,
SymbolShapeHint.FORCE_NONE, fixedSize, fixedSize, false);
assertNull(info);
Dimension minSize = fixedSize;
Dimension maxSize = new Dimension(32, 32);
info = SymbolInfo.lookup(35,
SymbolShapeHint.FORCE_NONE, minSize, maxSize, false);
assertNotNull(info);
assertEquals(26, info.getSymbolWidth());
assertEquals(26, info.getSymbolHeight());
info = SymbolInfo.lookup(40,
SymbolShapeHint.FORCE_NONE, minSize, maxSize, false);
assertNotNull(info);
assertEquals(26, info.getSymbolWidth());
assertEquals(26, info.getSymbolHeight());
info = SymbolInfo.lookup(45,
SymbolShapeHint.FORCE_NONE, minSize, maxSize, false);
assertNotNull(info);
assertEquals(32, info.getSymbolWidth());
assertEquals(32, info.getSymbolHeight());
info = SymbolInfo.lookup(63,
SymbolShapeHint.FORCE_NONE, minSize, maxSize, false);
assertNull(info);
}
}

View File

@@ -14,12 +14,12 @@
* limitations under the License.
*/
package com.google.zxing.datamatrix.encoder;
use super::EncoderContext;
interface Encoder {
pub trait Encoder {
int getEncodingMode();
fn getEncodingMode(&self) -> i32;
void encode(EncoderContext context);
fn encode(&self, context:&mut EncoderContext);
}

View File

@@ -0,0 +1,171 @@
/*
* Copyright 2006-2007 Jeremias Maerki.
*
* 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::{Dimension, Exceptions};
use super::{SymbolInfo, SymbolShapeHint, SymbolInfoLookup};
use encoding::{self, EncodingRef};
use unicode_segmentation::UnicodeSegmentation;
const ISO_8859_1_ENCODER: EncodingRef = encoding::all::ISO_8859_1;
pub struct EncoderContext<'a> {
symbol_lookup:Rc<SymbolInfoLookup<'a>>,
msg: String,
shape: SymbolShapeHint,
minSize: Option<Dimension>,
maxSize: Option<Dimension>,
codewords: String,
pos: u32,
newEncoding: i32,
symbolInfo: Option<&'a SymbolInfo>,
skipAtEnd: u32,
}
impl EncoderContext<'_> {
pub fn new(msg: &str) -> Result<Self, Exceptions> {
//From this point on Strings are not Unicode anymore!
// let msgBinary = ISO_8859_1_ENCODER.encode(msg, encoding::EncoderTrap::Strict).expect("encode to bytes");//msg.getBytes(StandardCharsets.ISO_8859_1);
// let sb = String::with_capacity(msgBinary.len());
// for (int i = 0, c = msgBinary.length; i < c; i++) {
// char ch = (char) (msgBinary[i] & 0xff);
// if (ch == '?' && msg.charAt(i) != '?') {
// throw new IllegalArgumentException("Message contains characters outside ISO-8859-1 encoding.");
// }
// sb.append(ch);
// }
let sb = if let Ok(encoded_bytes) =
ISO_8859_1_ENCODER.encode(msg, encoding::EncoderTrap::Strict)
{
ISO_8859_1_ENCODER
.decode(&encoded_bytes, encoding::DecoderTrap::Strict)
.expect("round trip decode should always work")
} else {
return Err(Exceptions::IllegalArgumentException(
"Message contains characters outside ISO-8859-1 encoding.".to_owned(),
));
};
Ok(Self {
symbol_lookup:Rc::new(SymbolInfoLookup::new()),
msg: sb,
shape: SymbolShapeHint::FORCE_NONE,
codewords: String::with_capacity(msg.len()),
newEncoding: -1,
minSize: None,
maxSize: None,
pos: 0,
symbolInfo: None,
skipAtEnd: 0,
})
}
pub fn setSymbolShape(&mut self, shape: SymbolShapeHint) {
self.shape = shape;
}
pub fn setSizeConstraints(&mut self, minSize: Dimension, maxSize: Dimension) {
self.minSize = Some(minSize);
self.maxSize = Some(maxSize);
}
pub fn getMessage(&self) -> &str {
&self.msg
}
pub fn setSkipAtEnd(&mut self, count: u32) {
self.skipAtEnd = count;
}
pub fn getCurrentChar(&self) -> &str {
self.msg.graphemes(true).nth(self.pos as usize).unwrap()
}
pub fn getCurrent(&self) -> &str {
self.msg.graphemes(true).nth(self.pos as usize).unwrap()
}
pub fn getCodewords(&self) -> &str {
&self.codewords
}
pub fn writeCodewords(&mut self, codewords: &str) {
self.codewords.push_str(codewords);
}
pub fn writeCodeword(&mut self, codeword: &str) {
self.codewords.push_str(codeword);
}
pub fn getCodewordCount(&self) -> usize {
self.codewords.len()
}
pub fn getNewEncoding(&self) -> i32 {
self.newEncoding
}
pub fn signalEncoderChange(&mut self, encoding: i32) {
self.newEncoding = encoding;
}
pub fn resetEncoderSignal(&mut self) {
self.newEncoding = -1;
}
pub fn hasMoreCharacters(&self) -> bool {
self.pos < self.getTotalMessageCharCount()
}
fn getTotalMessageCharCount(&self) -> u32 {
self.msg.len() as u32 - self.skipAtEnd
}
pub fn getRemainingCharacters(&self) -> u32 {
self.getTotalMessageCharCount() - self.pos
}
pub fn getSymbolInfo(&self) -> &Option<&SymbolInfo> {
&self.symbolInfo
}
pub fn updateSymbolInfo(&mut self) {
self.updateSymbolInfoWithLength(self.getCodewordCount());
}
pub fn updateSymbolInfoWithLength(&mut self, len: usize) {
if self.symbolInfo.is_none()
|| len > self.symbolInfo.as_ref().unwrap().getDataCapacity() as usize
{
self.symbolInfo = Some(
self.symbol_lookup.lookup_with_codewords_shape_size_fail(
len as u32,
self.shape,
&self.minSize,
&self.maxSize,
true,
)
.unwrap()
.unwrap(),
);
}
}
pub fn resetSymbolInfo(&mut self) {
self.symbolInfo = None;
}
}

View File

@@ -0,0 +1,9 @@
mod encoder;
mod encoder_context;
mod symbol_shape_hint;
mod symbol_info;
pub use encoder::*;
pub use encoder_context::*;
pub use symbol_shape_hint::*;
pub use symbol_info::*;

View File

@@ -0,0 +1,508 @@
/*
* Copyright 2006 Jeremias Maerki
*
* 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::{Dimension, Exceptions};
use super::SymbolShapeHint;
use lazy_static::lazy_static;
lazy_static! {
static ref PROD_SYMBOLS: Vec<SymbolInfo> = vec![
SymbolInfo::new(false, 3, 5, 8, 8, 1),
SymbolInfo::new(false, 5, 7, 10, 10, 1),
/*rect*/ SymbolInfo::new(true, 5, 7, 16, 6, 1),
SymbolInfo::new(false, 8, 10, 12, 12, 1),
/*rect*/ SymbolInfo::new(true, 10, 11, 14, 6, 2),
SymbolInfo::new(false, 12, 12, 14, 14, 1),
/*rect*/ SymbolInfo::new(true, 16, 14, 24, 10, 1),
SymbolInfo::new(false, 18, 14, 16, 16, 1),
SymbolInfo::new(false, 22, 18, 18, 18, 1),
/*rect*/ SymbolInfo::new(true, 22, 18, 16, 10, 2),
SymbolInfo::new(false, 30, 20, 20, 20, 1),
/*rect*/ SymbolInfo::new(true, 32, 24, 16, 14, 2),
SymbolInfo::new(false, 36, 24, 22, 22, 1),
SymbolInfo::new(false, 44, 28, 24, 24, 1),
/*rect*/ SymbolInfo::new(true, 49, 28, 22, 14, 2),
SymbolInfo::new(false, 62, 36, 14, 14, 4),
SymbolInfo::new(false, 86, 42, 16, 16, 4),
SymbolInfo::new(false, 114, 48, 18, 18, 4),
SymbolInfo::new(false, 144, 56, 20, 20, 4),
SymbolInfo::new(false, 174, 68, 22, 22, 4),
SymbolInfo::with_details(false, 204, 84, 24, 24, 4, 102, 42),
SymbolInfo::with_details(false, 280, 112, 14, 14, 16, 140, 56),
SymbolInfo::with_details(false, 368, 144, 16, 16, 16, 92, 36),
SymbolInfo::with_details(false, 456, 192, 18, 18, 16, 114, 48),
SymbolInfo::with_details(false, 576, 224, 20, 20, 16, 144, 56),
SymbolInfo::with_details(false, 696, 272, 22, 22, 16, 174, 68),
SymbolInfo::with_details(false, 816, 336, 24, 24, 16, 136, 56),
SymbolInfo::with_details(false, 1050, 408, 18, 18, 36, 175, 68),
SymbolInfo::with_details(false, 1304, 496, 20, 20, 36, 163, 62),
SymbolInfo::new_symbol_info_144(),
];
}
/**
* Symbol info table for DataMatrix.
*
* @version $Id$
*/
pub struct SymbolInfo {
rectangular: bool,
dataCapacity: u32,
errorCodewords: u32,
matrixWidth: u32,
matrixHeight: u32,
dataRegions: u32,
rsBlockData: i32,
rsBlockError: u32,
isSymbolInfo144: bool,
}
impl SymbolInfo {
pub fn new(
rectangular: bool,
dataCapacity: u32,
errorCodewords: u32,
matrixWidth: u32,
matrixHeight: u32,
dataRegions: u32,
) -> Self {
Self::with_details(
rectangular,
dataCapacity,
errorCodewords,
matrixWidth,
matrixHeight,
dataRegions,
dataCapacity as i32,
errorCodewords,
)
}
pub fn with_details(
rectangular: bool,
dataCapacity: u32,
errorCodewords: u32,
matrixWidth: u32,
matrixHeight: u32,
dataRegions: u32,
rsBlockData: i32,
rsBlockError: u32,
) -> Self {
Self {
rectangular,
dataCapacity,
errorCodewords,
matrixWidth,
matrixHeight,
dataRegions,
rsBlockData,
rsBlockError,
isSymbolInfo144: false,
}
}
pub fn new_symbol_info_144() -> Self {
let mut new_symbol = Self::with_details(false, 1558, 620, 22, 22, 36, -1, 62);
new_symbol.isSymbolInfo144 = true;
new_symbol
}
fn getHorizontalDataRegions(&self) -> Result<u32, Exceptions> {
match self.dataRegions {
1 => Ok(1),
2 | 4 => Ok(2),
16 => Ok(4),
36 => Ok(6),
_ => Err(Exceptions::IllegalStateException(
"Cannot handle this number of data regions".to_owned(),
)),
}
// switch (dataRegions) {
// case 1:
// return 1;
// case 2:
// case 4:
// return 2;
// case 16:
// return 4;
// case 36:
// return 6;
// default:
// throw new IllegalStateException("Cannot handle this number of data regions");
// }
}
fn getVerticalDataRegions(&self) -> Result<u32, Exceptions> {
match self.dataRegions {
1 | 2 => Ok(1),
4 => Ok(2),
16 => Ok(4),
36 => Ok(6),
_ => Err(Exceptions::IllegalStateException(
"Cannot handle this number of data regions".to_owned(),
)),
}
// switch (dataRegions) {
// case 1:
// case 2:
// return 1;
// case 4:
// return 2;
// case 16:
// return 4;
// case 36:
// return 6;
// default:
// throw new IllegalStateException("Cannot handle this number of data regions");
// }
}
pub fn getSymbolDataWidth(&self) -> Result<u32, Exceptions> {
Ok(self.getHorizontalDataRegions()? * self.matrixWidth)
}
pub fn getSymbolDataHeight(&self) -> Result<u32, Exceptions> {
Ok(self.getVerticalDataRegions()? * self.matrixHeight)
}
pub fn getSymbolWidth(&self) -> Result<u32, Exceptions> {
Ok(self.getSymbolDataWidth()? + (self.getHorizontalDataRegions()? * 2))
}
pub fn getSymbolHeight(&self) -> Result<u32, Exceptions> {
Ok(self.getSymbolDataHeight()? + (self.getVerticalDataRegions()? * 2))
}
pub fn getCodewordCount(&self) -> u32 {
self.dataCapacity + self.errorCodewords
}
pub fn getInterleavedBlockCount(&self) -> u32 {
if self.isSymbolInfo144 {
10
} else {
self.dataCapacity / self.rsBlockData as u32
}
}
pub fn getDataCapacity(&self) -> u32 {
self.dataCapacity
}
pub fn getErrorCodewords(&self) -> u32 {
self.errorCodewords
}
pub fn getDataLengthForInterleavedBlock(&self, index: u32) -> i32 {
if self.isSymbolInfo144 {
if index <= 8 {
156
} else {
155
}
} else {
self.rsBlockData
}
}
pub fn getErrorLengthForInterleavedBlock(&self, index: u32) -> u32 {
self.rsBlockError
}
// @Override
// public final String toString() {
// return (rectangular ? "Rectangular Symbol:" : "Square Symbol:") +
// " data region " + matrixWidth + 'x' + matrixHeight +
// ", symbol size " + getSymbolWidth() + 'x' + getSymbolHeight() +
// ", symbol data size " + getSymbolDataWidth() + 'x' + getSymbolDataHeight() +
// ", codewords " + dataCapacity + '+' + errorCodewords;
// }
}
impl fmt::Display for SymbolInfo {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"{} data region {}x{}, symbol size {}x{}, symbol data size {}x{}, codewords {}+{}",
if self.rectangular {
"Rectangular Symbol:"
} else {
"Square Symbol:"
},
self.matrixWidth,
self.matrixHeight,
self.getSymbolWidth().unwrap_or_default(),
self.getSymbolHeight().unwrap_or_default(),
self.getSymbolDataWidth().unwrap_or_default(),
self.getSymbolDataHeight().unwrap_or_default(),
self.dataCapacity,
self.errorCodewords
)
}
}
pub struct SymbolInfoLookup<'a>(Option<&'a Vec<SymbolInfo>>);
impl<'a> SymbolInfoLookup<'a> {
pub const fn new() -> Self {
Self(None)
}
/**
* Overrides the symbol info set used by this class. Used for testing purposes.
*
* @param override the symbol info set to use
*/
pub fn overrideSymbolSet(&mut self, override_symbols: &'a Vec<SymbolInfo>) {
self.0 = Some(override_symbols);
}
pub fn lookup(&self, dataCodewords: u32) -> Result<Option<&'a SymbolInfo>, Exceptions> {
self.lookup_with_codewords_shape_fail(dataCodewords, SymbolShapeHint::FORCE_NONE, true)
}
pub fn lookup_with_shape(
&self,
dataCodewords: u32,
shape: SymbolShapeHint,
) -> Result<Option<&'a SymbolInfo>, Exceptions> {
self.lookup_with_codewords_shape_fail(dataCodewords, shape, true)
}
pub fn lookup_codwords_rectangule_fail(
&self,
dataCodewords: u32,
allowRectangular: bool,
fail: bool,
) -> Result<Option<&'a SymbolInfo>, Exceptions> {
let shape = if allowRectangular {
SymbolShapeHint::FORCE_NONE
} else {
SymbolShapeHint::FORCE_SQUARE
};
self.lookup_with_codewords_shape_fail(dataCodewords, shape, fail)
}
fn lookup_with_codewords_shape_fail(
&self,
dataCodewords: u32,
shape: SymbolShapeHint,
fail: bool,
) -> Result<Option<&'a SymbolInfo>, Exceptions> {
self.lookup_with_codewords_shape_size_fail(dataCodewords, shape, &None, &None, fail)
}
pub fn lookup_with_codewords_shape_size_fail(
&self,
dataCodewords: u32,
shape: SymbolShapeHint,
minSize: &Option<Dimension>,
maxSize: &Option<Dimension>,
fail: bool,
// alternate_symbols_chart: Option<&'a Vec<SymbolInfo>>,
) -> Result<Option<&'a SymbolInfo>, Exceptions> {
let symbol_search_chart: &Vec<SymbolInfo> = if self.0.is_none() {
&PROD_SYMBOLS
} else {
self.0.as_ref().unwrap()
};
for symbol in symbol_search_chart {
// for (SymbolInfo symbol : symbols) {
if shape == SymbolShapeHint::FORCE_SQUARE && symbol.rectangular {
continue;
}
if shape == SymbolShapeHint::FORCE_RECTANGLE && !symbol.rectangular {
continue;
}
if minSize.is_some()
&& ((symbol.getSymbolWidth()? as usize) < minSize.as_ref().unwrap().getWidth()
|| (symbol.getSymbolHeight()? as usize) < minSize.as_ref().unwrap().getHeight())
{
continue;
}
if maxSize.is_some()
&& ((symbol.getSymbolWidth()? as usize) > maxSize.as_ref().unwrap().getWidth()
|| (symbol.getSymbolHeight()? as usize) > maxSize.as_ref().unwrap().getHeight())
{
continue;
}
if dataCodewords <= symbol.dataCapacity {
return Ok(Some(symbol));
}
}
if fail {
return Err(Exceptions::IllegalArgumentException(format!(
"Can't find a symbol arrangement that matches the message. Data codewords: {}",
dataCodewords
)));
}
Ok(None)
}
}
mod tests {
use crate::{
datamatrix::encoder::{SymbolInfo, SymbolShapeHint},
Dimension,
};
use super::SymbolInfoLookup;
const LOOKUP: SymbolInfoLookup = SymbolInfoLookup::new();
/**
* Tests the SymbolInfo class.
*/
#[test]
fn testSymbolInfo() {
let info = LOOKUP.lookup(3).expect("returns").expect("exists");
assert_eq!(5, info.getErrorCodewords());
assert_eq!(8, info.matrixWidth);
assert_eq!(8, info.matrixHeight);
assert_eq!(10, info.getSymbolWidth().expect("returns"));
assert_eq!(10, info.getSymbolHeight().expect("returns"));
let info = LOOKUP
.lookup_with_shape(3, SymbolShapeHint::FORCE_RECTANGLE)
.expect("returns")
.expect("exists");
assert_eq!(7, info.getErrorCodewords());
assert_eq!(16, info.matrixWidth);
assert_eq!(6, info.matrixHeight);
assert_eq!(18, info.getSymbolWidth().expect("returns"));
assert_eq!(8, info.getSymbolHeight().expect("returns"));
let info = LOOKUP.lookup(9).expect("returns").expect("exists");
assert_eq!(11, info.getErrorCodewords());
assert_eq!(14, info.matrixWidth);
assert_eq!(6, info.matrixHeight);
assert_eq!(32, info.getSymbolWidth().expect("returns"));
assert_eq!(8, info.getSymbolHeight().expect("returns"));
let info = LOOKUP
.lookup_with_shape(9, SymbolShapeHint::FORCE_SQUARE)
.expect("returns")
.expect("exists");
assert_eq!(12, info.getErrorCodewords());
assert_eq!(14, info.matrixWidth);
assert_eq!(14, info.matrixHeight);
assert_eq!(16, info.getSymbolWidth().expect("returns"));
assert_eq!(16, info.getSymbolHeight().expect("returns"));
assert!(LOOKUP.lookup(1559).is_err());
// try {
// SymbolInfo.lookup(1559);
// fail("There's no rectangular symbol for more than 1558 data codewords");
// } catch (IllegalArgumentException iae) {
// //expected
// }
assert!(LOOKUP
.lookup_with_shape(50, SymbolShapeHint::FORCE_RECTANGLE)
.is_err());
// try {
// SymbolInfo.lookup(50, SymbolShapeHint.FORCE_RECTANGLE);
// fail("There's no rectangular symbol for 50 data codewords");
// } catch (IllegalArgumentException iae) {
// //expected
// }
let info = LOOKUP.lookup(35).expect("returns").expect("exists");
assert_eq!(24, info.getSymbolWidth().expect("return"));
assert_eq!(24, info.getSymbolHeight().expect("return"));
let fixedSize = Dimension::new(26, 26).expect("new dimension");
let info = LOOKUP
.lookup_with_codewords_shape_size_fail(
35,
SymbolShapeHint::FORCE_NONE,
&Some(fixedSize),
&Some(fixedSize),
false,
)
.expect("returns");
assert!(info.is_some());
let info = info.unwrap();
assert_eq!(26, info.getSymbolWidth().expect("return"));
assert_eq!(26, info.getSymbolHeight().expect("return"));
let info = LOOKUP
.lookup_with_codewords_shape_size_fail(
45,
SymbolShapeHint::FORCE_NONE,
&Some(fixedSize),
&Some(fixedSize),
false,
)
.expect("return");
assert!(info.is_none());
let minSize = fixedSize;
let maxSize = Dimension::new(32, 32).expect("new dimension");
let info = LOOKUP
.lookup_with_codewords_shape_size_fail(
35,
SymbolShapeHint::FORCE_NONE,
&Some(minSize),
&Some(maxSize),
false,
)
.expect("return");
assert!(info.is_some());
let info = info.unwrap();
assert_eq!(26, info.getSymbolWidth().expect("return"));
assert_eq!(26, info.getSymbolHeight().expect("return"));
let info = LOOKUP
.lookup_with_codewords_shape_size_fail(
40,
SymbolShapeHint::FORCE_NONE,
&Some(minSize),
&Some(maxSize),
false,
)
.expect("return");
assert!(info.is_some());
let info = info.unwrap();
assert_eq!(26, info.getSymbolWidth().expect("return"));
assert_eq!(26, info.getSymbolHeight().expect("return"));
let info = LOOKUP
.lookup_with_codewords_shape_size_fail(
45,
SymbolShapeHint::FORCE_NONE,
&Some(minSize),
&Some(maxSize),
false,
)
.expect("return");
assert!(info.is_some());
let info = info.unwrap();
assert_eq!(32, info.getSymbolWidth().expect("return"));
assert_eq!(32, info.getSymbolHeight().expect("return"));
let info = LOOKUP
.lookup_with_codewords_shape_size_fail(
63,
SymbolShapeHint::FORCE_NONE,
&Some(minSize),
&Some(maxSize),
false,
)
.expect("return");
assert!(info.is_none());
}
}

View File

@@ -14,16 +14,13 @@
* limitations under the License.
*/
package com.google.zxing.datamatrix.encoder;
/**
* Enumeration for DataMatrix symbol shape hint. It can be used to force square or rectangular
* symbols.
*/
public enum SymbolShapeHint {
FORCE_NONE,
FORCE_SQUARE,
FORCE_RECTANGLE,
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum SymbolShapeHint {
FORCE_NONE,
FORCE_SQUARE,
FORCE_RECTANGLE,
}

View File

@@ -23,7 +23,7 @@ use crate::Exceptions;
/**
* Simply encapsulates a width and height.
*/
#[derive(Eq, PartialEq, Hash)]
#[derive(Eq, PartialEq, Hash, Copy, Clone)]
pub struct Dimension(usize, usize);
impl Dimension {