From de5936144103a07e77f1f593dfc71f5ff29c351b Mon Sep 17 00:00:00 2001 From: Henry Schimke Date: Sat, 5 Nov 2022 18:05:07 -0500 Subject: [PATCH] placement and pass --- src/datamatrix/encoder/DebugPlacement.java | 42 --- src/datamatrix/encoder/DefaultPlacement.java | 198 ------------ src/datamatrix/encoder/PlacementTestCase.java | 63 ---- src/datamatrix/encoder/default_placement.rs | 292 ++++++++++++++++++ src/datamatrix/encoder/mod.rs | 2 + 5 files changed, 294 insertions(+), 303 deletions(-) delete mode 100644 src/datamatrix/encoder/DebugPlacement.java delete mode 100644 src/datamatrix/encoder/DefaultPlacement.java delete mode 100644 src/datamatrix/encoder/PlacementTestCase.java create mode 100644 src/datamatrix/encoder/default_placement.rs diff --git a/src/datamatrix/encoder/DebugPlacement.java b/src/datamatrix/encoder/DebugPlacement.java deleted file mode 100644 index 60aed9c..0000000 --- a/src/datamatrix/encoder/DebugPlacement.java +++ /dev/null @@ -1,42 +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 DebugPlacement extends DefaultPlacement { - - DebugPlacement(String codewords, int numcols, int numrows) { - super(codewords, numcols, numrows); - } - - String[] toBitFieldStringArray() { - byte[] bits = getBits(); - int numrows = getNumrows(); - int numcols = getNumcols(); - String[] array = new String[numrows]; - int startpos = 0; - for (int row = 0; row < numrows; row++) { - StringBuilder sb = new StringBuilder(bits.length); - for (int i = 0; i < numcols; i++) { - sb.append(bits[startpos + i] == 1 ? '1' : '0'); - } - array[row] = sb.toString(); - startpos += numcols; - } - return array; - } - -} diff --git a/src/datamatrix/encoder/DefaultPlacement.java b/src/datamatrix/encoder/DefaultPlacement.java deleted file mode 100644 index c80867c..0000000 --- a/src/datamatrix/encoder/DefaultPlacement.java +++ /dev/null @@ -1,198 +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 java.util.Arrays; - -/** - * Symbol Character Placement Program. Adapted from Annex M.1 in ISO/IEC 16022:2000(E). - */ -public class DefaultPlacement { - - private final CharSequence codewords; - private final int numrows; - private final int numcols; - private final byte[] bits; - - /** - * Main constructor - * - * @param codewords the codewords to place - * @param numcols the number of columns - * @param numrows the number of rows - */ - public DefaultPlacement(CharSequence codewords, int numcols, int numrows) { - this.codewords = codewords; - this.numcols = numcols; - this.numrows = numrows; - this.bits = new byte[numcols * numrows]; - Arrays.fill(this.bits, (byte) -1); //Initialize with "not set" value - } - - final int getNumrows() { - return numrows; - } - - final int getNumcols() { - return numcols; - } - - final byte[] getBits() { - return bits; - } - - public final boolean getBit(int col, int row) { - return bits[row * numcols + col] == 1; - } - - private void setBit(int col, int row, boolean bit) { - bits[row * numcols + col] = (byte) (bit ? 1 : 0); - } - - private boolean noBit(int col, int row) { - return bits[row * numcols + col] < 0; - } - - public final void place() { - int pos = 0; - int row = 4; - int col = 0; - - do { - // repeatedly first check for one of the special corner cases, then... - if ((row == numrows) && (col == 0)) { - corner1(pos++); - } - if ((row == numrows - 2) && (col == 0) && ((numcols % 4) != 0)) { - corner2(pos++); - } - if ((row == numrows - 2) && (col == 0) && (numcols % 8 == 4)) { - corner3(pos++); - } - if ((row == numrows + 4) && (col == 2) && ((numcols % 8) == 0)) { - corner4(pos++); - } - // sweep upward diagonally, inserting successive characters... - do { - if ((row < numrows) && (col >= 0) && noBit(col, row)) { - utah(row, col, pos++); - } - row -= 2; - col += 2; - } while (row >= 0 && (col < numcols)); - row++; - col += 3; - - // and then sweep downward diagonally, inserting successive characters, ... - do { - if ((row >= 0) && (col < numcols) && noBit(col, row)) { - utah(row, col, pos++); - } - row += 2; - col -= 2; - } while ((row < numrows) && (col >= 0)); - row += 3; - col++; - - // ...until the entire array is scanned - } while ((row < numrows) || (col < numcols)); - - // Lastly, if the lower right-hand corner is untouched, fill in fixed pattern - if (noBit(numcols - 1, numrows - 1)) { - setBit(numcols - 1, numrows - 1, true); - setBit(numcols - 2, numrows - 2, true); - } - } - - private void module(int row, int col, int pos, int bit) { - if (row < 0) { - row += numrows; - col += 4 - ((numrows + 4) % 8); - } - if (col < 0) { - col += numcols; - row += 4 - ((numcols + 4) % 8); - } - // Note the conversion: - int v = codewords.charAt(pos); - v &= 1 << (8 - bit); - setBit(col, row, v != 0); - } - - /** - * Places the 8 bits of a utah-shaped symbol character in ECC200. - * - * @param row the row - * @param col the column - * @param pos character position - */ - private void utah(int row, int col, int pos) { - module(row - 2, col - 2, pos, 1); - module(row - 2, col - 1, pos, 2); - module(row - 1, col - 2, pos, 3); - module(row - 1, col - 1, pos, 4); - module(row - 1, col, pos, 5); - module(row, col - 2, pos, 6); - module(row, col - 1, pos, 7); - module(row, col, pos, 8); - } - - private void corner1(int pos) { - module(numrows - 1, 0, pos, 1); - module(numrows - 1, 1, pos, 2); - module(numrows - 1, 2, pos, 3); - module(0, numcols - 2, pos, 4); - module(0, numcols - 1, pos, 5); - module(1, numcols - 1, pos, 6); - module(2, numcols - 1, pos, 7); - module(3, numcols - 1, pos, 8); - } - - private void corner2(int pos) { - module(numrows - 3, 0, pos, 1); - module(numrows - 2, 0, pos, 2); - module(numrows - 1, 0, pos, 3); - module(0, numcols - 4, pos, 4); - module(0, numcols - 3, pos, 5); - module(0, numcols - 2, pos, 6); - module(0, numcols - 1, pos, 7); - module(1, numcols - 1, pos, 8); - } - - private void corner3(int pos) { - module(numrows - 3, 0, pos, 1); - module(numrows - 2, 0, pos, 2); - module(numrows - 1, 0, pos, 3); - module(0, numcols - 2, pos, 4); - module(0, numcols - 1, pos, 5); - module(1, numcols - 1, pos, 6); - module(2, numcols - 1, pos, 7); - module(3, numcols - 1, pos, 8); - } - - private void corner4(int pos) { - module(numrows - 1, 0, pos, 1); - module(numrows - 1, numcols - 1, pos, 2); - module(0, numcols - 3, pos, 3); - module(0, numcols - 2, pos, 4); - module(0, numcols - 1, pos, 5); - module(1, numcols - 3, pos, 6); - module(1, numcols - 2, pos, 7); - module(1, numcols - 1, pos, 8); - } - -} diff --git a/src/datamatrix/encoder/PlacementTestCase.java b/src/datamatrix/encoder/PlacementTestCase.java deleted file mode 100644 index 16fd0e5..0000000 --- a/src/datamatrix/encoder/PlacementTestCase.java +++ /dev/null @@ -1,63 +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 org.junit.Assert; -import org.junit.Test; - -import java.util.regex.Pattern; - -/** - * Tests the DataMatrix placement algorithm. - */ -public final class PlacementTestCase extends Assert { - - private static final Pattern SPACE = Pattern.compile(" "); - - @Test - public void testPlacement() { - String codewords = unvisualize("66 74 78 66 74 78 129 56 35 102 192 96 226 100 156 1 107 221"); //"AIMAIM" encoded - DebugPlacement placement = new DebugPlacement(codewords, 12, 12); - placement.place(); - String[] expected = { - "011100001111", - "001010101000", - "010001010100", - "001010100010", - "000111000100", - "011000010100", - "000100001101", - "011000010000", - "001100001101", - "100010010111", - "011101011010", - "001011001010"}; - String[] actual = placement.toBitFieldStringArray(); - for (int i = 0; i < actual.length; i++) { - assertEquals("Row " + i, expected[i], actual[i]); - } - } - - private static String unvisualize(CharSequence visualized) { - StringBuilder sb = new StringBuilder(); - for (String token : SPACE.split(visualized)) { - sb.append((char) Integer.parseInt(token)); - } - return sb.toString(); - } - -} diff --git a/src/datamatrix/encoder/default_placement.rs b/src/datamatrix/encoder/default_placement.rs new file mode 100644 index 0000000..9ef64e6 --- /dev/null +++ b/src/datamatrix/encoder/default_placement.rs @@ -0,0 +1,292 @@ +/* + * 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. + */ + +const EMPTY_BIT_VAL: u8 = 13; + +/** + * Symbol Character Placement Program. Adapted from Annex M.1 in ISO/IEC 16022:2000(E). + */ +pub struct DefaultPlacement { + codewords: String, + numrows: usize, + numcols: usize, + bits: Vec, +} +impl DefaultPlacement { + /** + * Main constructor + * + * @param codewords the codewords to place + * @param numcols the number of columns + * @param numrows the number of rows + */ + pub fn new(codewords: String, numcols: usize, numrows: usize) -> Self { + // this.codewords = codewords; + // this.numcols = numcols; + // this.numrows = numrows; + // this.bits = new byte[numcols * numrows]; + // Arrays.fill(this.bits, (byte) -1); //Initialize with "not set" value + Self { + codewords, + numrows, + numcols, + bits: vec![EMPTY_BIT_VAL; numcols * numrows], + } + } + + pub fn getNumrows(&self) -> usize { + self.numrows + } + + pub fn getNumcols(&self) -> usize { + self.numcols + } + + pub fn getBits(&self) -> &[u8] { + &self.bits + } + + pub fn getBit(&self, col: usize, row: usize) -> bool { + self.bits[row * self.numcols + col] == 1 + } + + pub fn setBit(&mut self, col: usize, row: usize, bit: bool) { + self.bits[row * self.numcols + col] = if bit { 1 } else { 0 }; + } + + pub fn noBit(&self, col: usize, row: usize) -> bool { + self.bits[row * self.numcols + col] == EMPTY_BIT_VAL + } + + pub fn place(&mut self) { + let mut pos = 0; + let mut row = 4_isize; + let mut col = 0_isize; + + loop { + // repeatedly first check for one of the special corner cases, then... + if (row == self.numrows as isize) && (col == 0) { + self.corner1(pos); + pos += 1; + } + if (row == self.numrows as isize - 2) && (col == 0) && ((self.numcols % 4) != 0) { + self.corner2(pos); + pos += 1; + } + if (row == self.numrows as isize - 2) && (col == 0) && (self.numcols % 8 == 4) { + self.corner3(pos); + pos += 1; + } + if (row == self.numrows as isize + 4) && (col == 2) && ((self.numcols % 8) == 0) { + self.corner4(pos); + pos += 1; + } + // sweep upward diagonally, inserting successive characters... + loop { + if (row < self.numrows as isize) + && (col >= 0) + && self.noBit(col as usize, row as usize) + { + self.utah(row, col, pos); + pos += 1; + } + row -= 2; + col += 2; + if !(row >= 0 && (col < self.numcols as isize)) { + break; + } + } //while (row >= 0 && (col < numcols)); + row += 1; + col += 3; + + // and then sweep downward diagonally, inserting successive characters, ... + loop { + if (row >= 0) + && (col < self.numcols as isize) + && self.noBit(col as usize, row as usize) + { + self.utah(row, col, pos); + pos += 1; + } + row += 2; + col -= 2; + + if !((row < self.numrows as isize) && (col >= 0)) { + break; + } + } //while ((row < numrows) && (col >= 0)); + row += 3; + col += 1; + + // ...until the entire array is scanned + if !((row < self.numrows as isize) || (col < self.numcols as isize)) { + break; + } + } // while ((row < numrows) || (col < numcols)); + + // Lastly, if the lower right-hand corner is untouched, fill in fixed pattern + if self.noBit(self.numcols - 1, self.numrows - 1) { + self.setBit(self.numcols - 1, self.numrows - 1, true); + self.setBit(self.numcols - 2, self.numrows - 2, true); + } + } + + fn module(&mut self, row: isize, col: isize, pos: usize, bit: u32) { + let mut row = row; + let mut col = col; + + if row < 0 { + row += self.numrows as isize; + col += 4 - ((self.numrows + 4) % 8) as isize; + } + if col < 0 { + col += self.numcols as isize; + row += 4 - ((self.numcols + 4) % 8) as isize; + } + // Note the conversion: + let mut v = self.codewords.chars().nth(pos).unwrap() as u32; + v &= 1 << (8 - bit); + self.setBit(col as usize, row as usize, v != 0); + } + + /** + * Places the 8 bits of a utah-shaped symbol character in ECC200. + * + * @param row the row + * @param col the column + * @param pos character position + */ + fn utah(&mut self, row: isize, col: isize, pos: usize) { + self.module(row - 2, col - 2, pos, 1); + self.module(row - 2, col - 1, pos, 2); + self.module(row - 1, col - 2, pos, 3); + self.module(row - 1, col - 1, pos, 4); + self.module(row - 1, col, pos, 5); + self.module(row, col - 2, pos, 6); + self.module(row, col - 1, pos, 7); + self.module(row, col, pos, 8); + } + + fn corner1(&mut self, pos: usize) { + self.module(self.numrows as isize - 1, 0, pos, 1); + self.module(self.numrows as isize - 1, 1, pos, 2); + self.module(self.numrows as isize - 1, 2, pos, 3); + self.module(0, self.numcols as isize - 2, pos, 4); + self.module(0, self.numcols as isize - 1, pos, 5); + self.module(1, self.numcols as isize - 1, pos, 6); + self.module(2, self.numcols as isize - 1, pos, 7); + self.module(3, self.numcols as isize - 1, pos, 8); + } + + fn corner2(&mut self, pos: usize) { + self.module(self.numrows as isize - 3, 0, pos, 1); + self.module(self.numrows as isize - 2, 0, pos, 2); + self.module(self.numrows as isize - 1, 0, pos, 3); + self.module(0, self.numcols as isize - 4, pos, 4); + self.module(0, self.numcols as isize - 3, pos, 5); + self.module(0, self.numcols as isize - 2, pos, 6); + self.module(0, self.numcols as isize - 1, pos, 7); + self.module(1, self.numcols as isize - 1, pos, 8); + } + + fn corner3(&mut self, pos: usize) { + self.module(self.numrows as isize - 3, 0, pos, 1); + self.module(self.numrows as isize - 2, 0, pos, 2); + self.module(self.numrows as isize - 1, 0, pos, 3); + self.module(0, self.numcols as isize - 2, pos, 4); + self.module(0, self.numcols as isize - 1, pos, 5); + self.module(1, self.numcols as isize - 1, pos, 6); + self.module(2, self.numcols as isize - 1, pos, 7); + self.module(3, self.numcols as isize - 1, pos, 8); + } + + fn corner4(&mut self, pos: usize) { + self.module(self.numrows as isize - 1, 0, pos, 1); + self.module(self.numrows as isize - 1, self.numcols as isize - 1, pos, 2); + self.module(0, self.numcols as isize - 3, pos, 3); + self.module(0, self.numcols as isize - 2, pos, 4); + self.module(0, self.numcols as isize - 1, pos, 5); + self.module(1, self.numcols as isize - 3, pos, 6); + self.module(1, self.numcols as isize - 2, pos, 7); + self.module(1, self.numcols as isize - 1, pos, 8); + } + + fn toBitFieldStringArray(&self) -> Vec { + let bits = self.getBits(); + let numrows = self.getNumrows(); + let numcols = self.getNumcols(); + let mut array = Vec::with_capacity(numrows); //;[numrows]; + let mut startpos = 0; + for _row in 0..numrows { + // for (int row = 0; row < numrows; row++) { + let mut sb = String::with_capacity(bits.len()); + for i in 0..numcols { + // for (int i = 0; i < numcols; i++) { + sb.push(if bits[startpos + i] == 1 { '1' } else { '0' }); + } + //array[row] = sb.toString(); + array.push(sb); + startpos += numcols; + } + + array + } +} + +#[cfg(test)] +mod test_placement { + //private static final Pattern SPACE = Pattern.compile(" "); + + use super::DefaultPlacement; + + #[test] + fn testPlacement() { + let codewords = unvisualize("66 74 78 66 74 78 129 56 35 102 192 96 226 100 156 1 107 221"); //"AIMAIM" encoded + let mut placement = DefaultPlacement::new(codewords, 12, 12); + placement.place(); + let expected = [ + "011100001111", + "001010101000", + "010001010100", + "001010100010", + "000111000100", + "011000010100", + "000100001101", + "011000010000", + "001100001101", + "100010010111", + "011101011010", + "001011001010", + ]; + let actual = placement.toBitFieldStringArray(); + for i in 0..actual.len() { + // for (int i = 0; i < actual.length; i++) { + assert_eq!(expected[i], actual[i], "Row {}", i); + } + } + + fn unvisualize(visualized: &str) -> String { + let mut sb = String::new(); + for token in visualized.split(" ") { + // for (String token : SPACE.split(visualized)) { + let tkn: u32 = token.parse().unwrap(); + sb.push(char::from_u32(tkn).unwrap()); + // sb.push((char) Integer.parseInt(token)); + } + + sb + } +} diff --git a/src/datamatrix/encoder/mod.rs b/src/datamatrix/encoder/mod.rs index da25586..6ddd6f1 100644 --- a/src/datamatrix/encoder/mod.rs +++ b/src/datamatrix/encoder/mod.rs @@ -5,11 +5,13 @@ pub mod high_level_encoder; pub mod minimal_encoder; mod symbol_info; mod symbol_shape_hint; +mod default_placement; pub use encoder::*; pub use encoder_context::*; pub use symbol_info::*; pub use symbol_shape_hint::*; +pub use default_placement::*; mod c40_encoder; pub use c40_encoder::*;