From e5abca3884fe0fa4f60e4b8eb7e68d9038c15545 Mon Sep 17 00:00:00 2001 From: Henry Schimke Date: Sat, 1 Oct 2022 16:24:53 -0500 Subject: [PATCH] QrCode struct and associated types ported NOPASS --- Cargo.toml | 1 + src/qrcode/decoder/ModeTestCase.java | 52 --------- src/qrcode/decoder/ModeTestCase.rs | 51 +++++++++ src/qrcode/decoder/VersionTestCase.java | 78 -------------- src/qrcode/decoder/VersionTestCase.rs | 85 +++++++++++++++ src/qrcode/decoder/format_information.rs | 6 +- src/qrcode/decoder/mod.rs | 4 + src/qrcode/decoder/mode.rs | 1 + src/qrcode/decoder/version.rs | 38 ++++--- src/qrcode/encoder/ByteMatrix.java | 99 ------------------ src/qrcode/encoder/QRCodeTestCase.java | 128 ----------------------- src/qrcode/encoder/QRCodeTestCase.rs | 128 +++++++++++++++++++++++ src/qrcode/encoder/byte_matrix.rs | 112 ++++++++++++++++++++ src/qrcode/encoder/mod.rs | 7 +- src/qrcode/encoder/qr_code.rs | 114 +++++++++++--------- 15 files changed, 476 insertions(+), 428 deletions(-) delete mode 100644 src/qrcode/decoder/ModeTestCase.java create mode 100644 src/qrcode/decoder/ModeTestCase.rs delete mode 100644 src/qrcode/decoder/VersionTestCase.java create mode 100644 src/qrcode/decoder/VersionTestCase.rs delete mode 100644 src/qrcode/encoder/ByteMatrix.java delete mode 100644 src/qrcode/encoder/QRCodeTestCase.java create mode 100644 src/qrcode/encoder/QRCodeTestCase.rs create mode 100644 src/qrcode/encoder/byte_matrix.rs diff --git a/Cargo.toml b/Cargo.toml index b95206d..1002671 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,6 +11,7 @@ exclude = [ [dependencies] regex = "1.6" fancy-regex = "0.10" +lazy_static = "1.4.0" encoding = "0.2" rand = "0.8.5" urlencoding = "2.1.2" diff --git a/src/qrcode/decoder/ModeTestCase.java b/src/qrcode/decoder/ModeTestCase.java deleted file mode 100644 index 15636d2..0000000 --- a/src/qrcode/decoder/ModeTestCase.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright 2008 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.qrcode.decoder; - -import org.junit.Assert; -import org.junit.Test; - -/** - * @author Sean Owen - */ -public final class ModeTestCase extends Assert { - - @Test - public void testForBits() { - assertSame(Mode.TERMINATOR, Mode.forBits(0x00)); - assertSame(Mode.NUMERIC, Mode.forBits(0x01)); - assertSame(Mode.ALPHANUMERIC, Mode.forBits(0x02)); - assertSame(Mode.BYTE, Mode.forBits(0x04)); - assertSame(Mode.KANJI, Mode.forBits(0x08)); - } - - @Test(expected = IllegalArgumentException.class) - public void testBadMode() { - Mode.forBits(0x10); - } - - @Test - public void testCharacterCount() { - // Spot check a few values - assertEquals(10, Mode.NUMERIC.getCharacterCountBits(Version.getVersionForNumber(5))); - assertEquals(12, Mode.NUMERIC.getCharacterCountBits(Version.getVersionForNumber(26))); - assertEquals(14, Mode.NUMERIC.getCharacterCountBits(Version.getVersionForNumber(40))); - assertEquals(9, Mode.ALPHANUMERIC.getCharacterCountBits(Version.getVersionForNumber(6))); - assertEquals(8, Mode.BYTE.getCharacterCountBits(Version.getVersionForNumber(7))); - assertEquals(8, Mode.KANJI.getCharacterCountBits(Version.getVersionForNumber(8))); - } - -} diff --git a/src/qrcode/decoder/ModeTestCase.rs b/src/qrcode/decoder/ModeTestCase.rs new file mode 100644 index 0000000..db93ff2 --- /dev/null +++ b/src/qrcode/decoder/ModeTestCase.rs @@ -0,0 +1,51 @@ +/* + * Copyright 2008 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::qrcode::decoder::Version; + +use super::Mode; + + +/** + * @author Sean Owen + */ + + #[test] + fn testForBits() { + assert_eq!(Mode::TERMINATOR, Mode::forBits(0x00).unwrap()); + assert_eq!(Mode::NUMERIC, Mode::forBits(0x01).unwrap()); + assert_eq!(Mode::ALPHANUMERIC, Mode::forBits(0x02).unwrap()); + assert_eq!(Mode::BYTE, Mode::forBits(0x04).unwrap()); + assert_eq!(Mode::KANJI, Mode::forBits(0x08).unwrap()); + } + + #[test] + #[should_panic] + fn testBadMode() { + assert!(Mode::forBits(0x10).is_ok()); + } + + #[test] + fn testCharacterCount() { + // Spot check a few values + assert_eq!(10, Mode::NUMERIC.getCharacterCountBits(Version::getVersionForNumber(5).unwrap())); + assert_eq!(12, Mode::NUMERIC.getCharacterCountBits(Version::getVersionForNumber(26).unwrap())); + assert_eq!(14, Mode::NUMERIC.getCharacterCountBits(Version::getVersionForNumber(40).unwrap())); + assert_eq!(9, Mode::ALPHANUMERIC.getCharacterCountBits(Version::getVersionForNumber(6).unwrap())); + assert_eq!(8, Mode::BYTE.getCharacterCountBits(Version::getVersionForNumber(7).unwrap())); + assert_eq!(8, Mode::KANJI.getCharacterCountBits(Version::getVersionForNumber(8).unwrap())); + } + diff --git a/src/qrcode/decoder/VersionTestCase.java b/src/qrcode/decoder/VersionTestCase.java deleted file mode 100644 index 4df7d4f..0000000 --- a/src/qrcode/decoder/VersionTestCase.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright 2008 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.qrcode.decoder; - -import org.junit.Assert; -import org.junit.Test; - -/** - * @author Sean Owen - */ -public final class VersionTestCase extends Assert { - - @Test(expected = IllegalArgumentException.class) - public void testBadVersion() { - Version.getVersionForNumber(0); - } - - @Test - public void testVersionForNumber() { - for (int i = 1; i <= 40; i++) { - checkVersion(Version.getVersionForNumber(i), i, 4 * i + 17); - } - } - - private static void checkVersion(Version version, int number, int dimension) { - assertNotNull(version); - assertEquals(number, version.getVersionNumber()); - assertNotNull(version.getAlignmentPatternCenters()); - if (number > 1) { - assertTrue(version.getAlignmentPatternCenters().length > 0); - } - assertEquals(dimension, version.getDimensionForVersion()); - assertNotNull(version.getECBlocksForLevel(ErrorCorrectionLevel.H)); - assertNotNull(version.getECBlocksForLevel(ErrorCorrectionLevel.L)); - assertNotNull(version.getECBlocksForLevel(ErrorCorrectionLevel.M)); - assertNotNull(version.getECBlocksForLevel(ErrorCorrectionLevel.Q)); - assertNotNull(version.buildFunctionPattern()); - } - - @Test - public void testGetProvisionalVersionForDimension() throws Exception { - for (int i = 1; i <= 40; i++) { - assertEquals(i, Version.getProvisionalVersionForDimension(4 * i + 17).getVersionNumber()); - } - } - - @Test - public void testDecodeVersionInformation() { - // Spot check - doTestVersion(7, 0x07C94); - doTestVersion(12, 0x0C762); - doTestVersion(17, 0x1145D); - doTestVersion(22, 0x168C9); - doTestVersion(27, 0x1B08E); - doTestVersion(32, 0x209D5); - } - - private static void doTestVersion(int expectedVersion, int mask) { - Version version = Version.decodeVersionInformation(mask); - assertNotNull(version); - assertEquals(expectedVersion, version.getVersionNumber()); - } - -} diff --git a/src/qrcode/decoder/VersionTestCase.rs b/src/qrcode/decoder/VersionTestCase.rs new file mode 100644 index 0000000..5060be0 --- /dev/null +++ b/src/qrcode/decoder/VersionTestCase.rs @@ -0,0 +1,85 @@ +/* + * Copyright 2008 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::{qrcode::decoder::{Version, ErrorCorrectionLevel}, Exceptions}; + + +/** + * @author Sean Owen + */ + + + #[test] + #[should_panic] + fn testBadVersion() { + assert!(Version::getVersionForNumber(0).is_ok()); + } + + #[test] + fn testVersionForNumber() { + for i in 1..=40 { + // for (int i = 1; i <= 40; i++) { + checkVersion(Version::getVersionForNumber(i), i, 4 * i + 17); + } + } + + fn checkVersion( version:Result<&Version,Exceptions>, number:u32, dimension:u32) { + assert!(version.is_ok()); + let version = version.unwrap(); + assert_eq!(number, version.getVersionNumber()); + // assertNotNull(version.getAlignmentPatternCenters()); + if (number > 1) { + assert!(version.getAlignmentPatternCenters().len() > 0); + } + assert_eq!(dimension, version.getDimensionForVersion()); + let _tmp = version.getECBlocksForLevel(ErrorCorrectionLevel::H); + let _tmp = version.getECBlocksForLevel(ErrorCorrectionLevel::L); + let _tmp = version.getECBlocksForLevel(ErrorCorrectionLevel::M); + let _tmp = version.getECBlocksForLevel(ErrorCorrectionLevel::Q); + let _tmp = version.buildFunctionPattern(); + + // assertNotNull(version.getECBlocksForLevel(ErrorCorrectionLevel::H)); + // assertNotNull(version.getECBlocksForLevel(ErrorCorrectionLevel::L)); + // assertNotNull(version.getECBlocksForLevel(ErrorCorrectionLevel::M)); + // assertNotNull(version.getECBlocksForLevel(ErrorCorrectionLevel::Q)); + // assertNotNull(version.buildFunctionPattern()); + } + + #[test] + fn testGetProvisionalVersionForDimension() { + for i in 1..=40 { + // for (int i = 1; i <= 40; i++) { + assert_eq!(i, Version::getProvisionalVersionForDimension(4 * i + 17).expect("must exist for supplied values").getVersionNumber()); + } + } + + #[test] + fn testDecodeVersionInformation() { + // Spot check + doTestVersion(7, 0x07C94); + doTestVersion(12, 0x0C762); + doTestVersion(17, 0x1145D); + doTestVersion(22, 0x168C9); + doTestVersion(27, 0x1B08E); + doTestVersion(32, 0x209D5); + } + + fn doTestVersion( expectedVersion:u32, mask:u32) { + let version = Version::decodeVersionInformation(mask); + assert!(version.is_ok()); + assert_eq!(expectedVersion, version.unwrap().getVersionNumber()); + } + diff --git a/src/qrcode/decoder/format_information.rs b/src/qrcode/decoder/format_information.rs index 415f704..1237078 100644 --- a/src/qrcode/decoder/format_information.rs +++ b/src/qrcode/decoder/format_information.rs @@ -118,8 +118,8 @@ impl FormatInformation { masked_format_info2: u32, ) -> Option { // Find the int in FORMAT_INFO_DECODE_LOOKUP with fewest bits differing - let best_difference = u32::MAX; - let best_format_info = 0; + let mut best_difference = u32::MAX; + let mut best_format_info = 0; for decodeInfo in FORMAT_INFO_DECODE_LOOKUP { // for (int[] decodeInfo : FORMAT_INFO_DECODE_LOOKUP) { let targetInfo = decodeInfo[0]; @@ -127,7 +127,7 @@ impl FormatInformation { // Found an exact match return Some(FormatInformation::new(decodeInfo[1] as u8)); } - let bits_difference = Self::numBitsDiffering(masked_format_info1, targetInfo); + let mut bits_difference = Self::numBitsDiffering(masked_format_info1, targetInfo); if bits_difference < best_difference { best_format_info = decodeInfo[1] as u8; best_difference = bits_difference; diff --git a/src/qrcode/decoder/mod.rs b/src/qrcode/decoder/mod.rs index 6a3891f..0ae2763 100644 --- a/src/qrcode/decoder/mod.rs +++ b/src/qrcode/decoder/mod.rs @@ -5,6 +5,10 @@ mod format_information; #[cfg(test)] mod ErrorCorrectionLevelTestCase; +#[cfg(test)] +mod ModeTestCase; +#[cfg(test)] +mod VersionTestCase; pub use version::*; pub use mode::*; diff --git a/src/qrcode/decoder/mode.rs b/src/qrcode/decoder/mode.rs index 1c4e624..99d4b48 100644 --- a/src/qrcode/decoder/mode.rs +++ b/src/qrcode/decoder/mode.rs @@ -24,6 +24,7 @@ use super::Version; * * @author Sean Owen */ +#[derive(Debug, PartialEq, Eq)] pub enum Mode { TERMINATOR, //(new int[]{0, 0, 0}, 0x00), // Not really a mode... NUMERIC, //(new int[]{10, 12, 14}, 0x01), diff --git a/src/qrcode/decoder/version.rs b/src/qrcode/decoder/version.rs index f507ff4..c3665e5 100755 --- a/src/qrcode/decoder/version.rs +++ b/src/qrcode/decoder/version.rs @@ -20,6 +20,12 @@ use crate::{common::BitMatrix, Exceptions}; use super::{ErrorCorrectionLevel, FormatInformation}; +use lazy_static::lazy_static; + +lazy_static! { + static ref VERSIONS: Vec = Version::buildVersions(); +} + /** * See ISO 18004:2006 Annex D. * Element i represents the raw version bits that specify version i + 7 @@ -31,7 +37,7 @@ const VERSION_DECODE_INFO: [u32; 34] = [ 0x2542E, 0x26A64, 0x27541, 0x28C69, ]; -const VERSIONS: Vec = Version::buildVersions(); +// const VERSIONS: &'static[Version] = &Version::buildVersions(); /** * See ISO 18004:2006 Annex D * @@ -45,12 +51,8 @@ pub struct Version { totalCodewords: u32, } impl Version { - const fn new( - versionNumber: u32, - alignmentPatternCenters: Vec, - ecBlocks: Vec, - ) -> Self { - let total = 0; + fn new(versionNumber: u32, alignmentPatternCenters: Vec, ecBlocks: Vec) -> Self { + let mut total = 0; let ecCodewords = ecBlocks[0].getECCodewordsPerBlock(); let ecbArray = ecBlocks[0].getECBlocks(); let mut i = 0; @@ -96,7 +98,9 @@ impl Version { * @return Version for a QR Code of that dimension * @throws FormatException if dimension is not 1 mod 4 */ - pub fn getProvisionalVersionForDimension(dimension: u32) -> Result { + pub fn getProvisionalVersionForDimension( + dimension: u32, + ) -> Result<&'static Version, Exceptions> { if dimension % 4 != 1 { return Err(Exceptions::FormatException( "dimension incorrect".to_owned(), @@ -110,18 +114,18 @@ impl Version { // } } - pub fn getVersionForNumber(versionNumber: u32) -> Result { + pub fn getVersionForNumber(versionNumber: u32) -> Result<&'static Version, Exceptions> { if versionNumber < 1 || versionNumber > 40 { return Err(Exceptions::IllegalArgumentException( "version out of spec".to_owned(), )); } - Ok(VERSIONS[versionNumber as usize - 1]) + Ok(&VERSIONS[versionNumber as usize - 1]) } - pub fn decodeVersionInformation(versionBits: u32) -> Result { - let bestDifference = u32::MAX; - let bestVersion = 0; + pub fn decodeVersionInformation(versionBits: u32) -> Result<&'static Version, Exceptions> { + let mut bestDifference = u32::MAX; + let mut bestVersion = 0; for i in 0..VERSION_DECODE_INFO.len() as u32 { // for (int i = 0; i < VERSION_DECODE_INFO.length; i++) { let targetVersion = VERSION_DECODE_INFO[i as usize]; @@ -151,7 +155,7 @@ impl Version { */ pub fn buildFunctionPattern(&self) -> BitMatrix { let dimension = self.getDimensionForVersion(); - let bitMatrix = BitMatrix::with_single_dimension(dimension); + let mut bitMatrix = BitMatrix::with_single_dimension(dimension); // Top left finder pattern + separator + format bitMatrix.setRegion(0, 0, 9, 9); @@ -192,7 +196,7 @@ impl Version { /** * See ISO 18004:2006 6.5.1 Table 9 */ - pub const fn buildVersions() -> Vec { + pub fn buildVersions() -> Vec { Vec::from([ Version::new( 1, @@ -942,8 +946,8 @@ impl ECBlocks { } pub fn getNumBlocks(&self) -> u32 { - let total = 0; - for ecBlock in self.ecBlocks { + let mut total = 0; + for ecBlock in &self.ecBlocks { // for (ECB ecBlock : ecBlocks) { total += ecBlock.getCount(); } diff --git a/src/qrcode/encoder/ByteMatrix.java b/src/qrcode/encoder/ByteMatrix.java deleted file mode 100644 index 35f344c..0000000 --- a/src/qrcode/encoder/ByteMatrix.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright 2008 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.qrcode.encoder; - -import java.util.Arrays; - -/** - * JAVAPORT: The original code was a 2D array of ints, but since it only ever gets assigned - * -1, 0, and 1, I'm going to use less memory and go with bytes. - * - * @author dswitkin@google.com (Daniel Switkin) - */ -public final class ByteMatrix { - - private final byte[][] bytes; - private final int width; - private final int height; - - public ByteMatrix(int width, int height) { - bytes = new byte[height][width]; - this.width = width; - this.height = height; - } - - public int getHeight() { - return height; - } - - public int getWidth() { - return width; - } - - public byte get(int x, int y) { - return bytes[y][x]; - } - - /** - * @return an internal representation as bytes, in row-major order. array[y][x] represents point (x,y) - */ - public byte[][] getArray() { - return bytes; - } - - public void set(int x, int y, byte value) { - bytes[y][x] = value; - } - - public void set(int x, int y, int value) { - bytes[y][x] = (byte) value; - } - - public void set(int x, int y, boolean value) { - bytes[y][x] = (byte) (value ? 1 : 0); - } - - public void clear(byte value) { - for (byte[] aByte : bytes) { - Arrays.fill(aByte, value); - } - } - - @Override - public String toString() { - StringBuilder result = new StringBuilder(2 * width * height + 2); - for (int y = 0; y < height; ++y) { - byte[] bytesY = bytes[y]; - for (int x = 0; x < width; ++x) { - switch (bytesY[x]) { - case 0: - result.append(" 0"); - break; - case 1: - result.append(" 1"); - break; - default: - result.append(" "); - break; - } - } - result.append('\n'); - } - return result.toString(); - } - -} diff --git a/src/qrcode/encoder/QRCodeTestCase.java b/src/qrcode/encoder/QRCodeTestCase.java deleted file mode 100644 index dc198d5..0000000 --- a/src/qrcode/encoder/QRCodeTestCase.java +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Copyright 2008 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.qrcode.encoder; - -import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel; -import com.google.zxing.qrcode.decoder.Mode; -import com.google.zxing.qrcode.decoder.Version; -import org.junit.Assert; -import org.junit.Test; - -/** - * @author satorux@google.com (Satoru Takabayashi) - creator - * @author mysen@google.com (Chris Mysen) - ported from C++ - */ -public final class QRCodeTestCase extends Assert { - - @Test - public void test() { - QRCode qrCode = new QRCode(); - - // First, test simple setters and getters. - // We use numbers of version 7-H. - qrCode.setMode(Mode.BYTE); - qrCode.setECLevel(ErrorCorrectionLevel.H); - qrCode.setVersion(Version.getVersionForNumber(7)); - qrCode.setMaskPattern(3); - - assertSame(Mode.BYTE, qrCode.getMode()); - assertSame(ErrorCorrectionLevel.H, qrCode.getECLevel()); - assertEquals(7, qrCode.getVersion().getVersionNumber()); - assertEquals(3, qrCode.getMaskPattern()); - - // Prepare the matrix. - ByteMatrix matrix = new ByteMatrix(45, 45); - // Just set bogus zero/one values. - for (int y = 0; y < 45; ++y) { - for (int x = 0; x < 45; ++x) { - matrix.set(x, y, (y + x) % 2); - } - } - - // Set the matrix. - qrCode.setMatrix(matrix); - assertSame(matrix, qrCode.getMatrix()); - } - - @Test - public void testToString1() { - QRCode qrCode = new QRCode(); - String expected = - "<<\n" + - " mode: null\n" + - " ecLevel: null\n" + - " version: null\n" + - " maskPattern: -1\n" + - " matrix: null\n" + - ">>\n"; - assertEquals(expected, qrCode.toString()); - } - - @Test - public void testToString2() { - QRCode qrCode = new QRCode(); - qrCode.setMode(Mode.BYTE); - qrCode.setECLevel(ErrorCorrectionLevel.H); - qrCode.setVersion(Version.getVersionForNumber(1)); - qrCode.setMaskPattern(3); - ByteMatrix matrix = new ByteMatrix(21, 21); - for (int y = 0; y < 21; ++y) { - for (int x = 0; x < 21; ++x) { - matrix.set(x, y, (y + x) % 2); - } - } - qrCode.setMatrix(matrix); - String expected = "<<\n" + - " mode: BYTE\n" + - " ecLevel: H\n" + - " version: 1\n" + - " maskPattern: 3\n" + - " matrix:\n" + - " 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0\n" + - " 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1\n" + - " 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0\n" + - " 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1\n" + - " 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0\n" + - " 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1\n" + - " 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0\n" + - " 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1\n" + - " 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0\n" + - " 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1\n" + - " 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0\n" + - " 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1\n" + - " 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0\n" + - " 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1\n" + - " 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0\n" + - " 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1\n" + - " 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0\n" + - " 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1\n" + - " 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0\n" + - " 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1\n" + - " 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0\n" + - ">>\n"; - assertEquals(expected, qrCode.toString()); - } - - @Test - public void testIsValidMaskPattern() { - assertFalse(QRCode.isValidMaskPattern(-1)); - assertTrue(QRCode.isValidMaskPattern(0)); - assertTrue(QRCode.isValidMaskPattern(7)); - assertFalse(QRCode.isValidMaskPattern(8)); - } - -} diff --git a/src/qrcode/encoder/QRCodeTestCase.rs b/src/qrcode/encoder/QRCodeTestCase.rs new file mode 100644 index 0000000..8b01c4b --- /dev/null +++ b/src/qrcode/encoder/QRCodeTestCase.rs @@ -0,0 +1,128 @@ +/* + * Copyright 2008 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::qrcode::{decoder::{Mode, ErrorCorrectionLevel, Version}, encoder::ByteMatrix}; + +use super::QRCode; + + +/** + * @author satorux@google.com (Satoru Takabayashi) - creator + * @author mysen@google.com (Chris Mysen) - ported from C++ + */ + + +#[test] + fn test() { + let mut qrCode = QRCode::new(); + + // First, test simple setters and getters. + // We use numbers of version 7-H. + qrCode.setMode(Mode::BYTE); + qrCode.setECLevel(ErrorCorrectionLevel::H); + qrCode.setVersion(Version::getVersionForNumber(7).expect("must exist")); + qrCode.setMaskPattern(3); + + assert_eq!(&Mode::BYTE, qrCode.getMode().as_ref().unwrap()); + assert_eq!(ErrorCorrectionLevel::H, qrCode.getECLevel().unwrap()); + assert_eq!(7, qrCode.getVersion().as_ref().unwrap().getVersionNumber()); + assert_eq!(3, qrCode.getMaskPattern()); + + // Prepare the matrix. + let mut matrix = ByteMatrix::new(45, 45); + // Just set bogus zero/one values. + for y in 0..45 { + // for (int y = 0; y < 45; ++y) { + for x in 0..45 { + // for (int x = 0; x < 45; ++x) { + matrix.set(x, y, ((y + x) % 2) as u8); + } + } + + // Set the matrix. + qrCode.setMatrix(matrix.clone()); + assert_eq!(&matrix, qrCode.getMatrix().as_ref().unwrap()); + } + + #[test] + fn testToString1() { + let qrCode = QRCode::new(); + let expected = + "<<\n\ + mode: null\n\ + ecLevel: null\n\ + version: null\n\ + maskPattern: -1\n\ + matrix: null\n\ +>>\n"; + assert_eq!(expected, qrCode.to_string()); + } + + #[test] + fn testToString2() { + let mut qrCode = QRCode::new(); + qrCode.setMode(Mode::BYTE); + qrCode.setECLevel(ErrorCorrectionLevel::H); + qrCode.setVersion(Version::getVersionForNumber(1).expect("predefined value must exist")); + qrCode.setMaskPattern(3); + let mut matrix = ByteMatrix::new(21, 21); + for y in 0..21 { + // for (int y = 0; y < 21; ++y) { + for x in 0..21 { + // for (int x = 0; x < 21; ++x) { + matrix.set(x, y, ((y + x) % 2) as u8); + } + } + qrCode.setMatrix(matrix); + let expected = "<<\n\ + mode: BYTE\n\ + ecLevel: H\n\ + version: 1\n\ + maskPattern: 3\n\ + matrix:\n\ + 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0\n\ + 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1\n\ + 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0\n\ + 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1\n\ + 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0\n\ + 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1\n\ + 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0\n\ + 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1\n\ + 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0\n\ + 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1\n\ + 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0\n\ + 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1\n\ + 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0\n\ + 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1\n\ + 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0\n\ + 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1\n\ + 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0\n\ + 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1\n\ + 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0\n\ + 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1\n\ + 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0\n\ +>>\n"; + assert_eq!(expected, qrCode.to_string()); + } + + #[test] + fn testIsValidMaskPattern() { + assert!(!QRCode::isValidMaskPattern(-1)); + assert!(QRCode::isValidMaskPattern(0)); + assert!(QRCode::isValidMaskPattern(7)); + assert!(!QRCode::isValidMaskPattern(8)); + } + diff --git a/src/qrcode/encoder/byte_matrix.rs b/src/qrcode/encoder/byte_matrix.rs new file mode 100644 index 0000000..8734f65 --- /dev/null +++ b/src/qrcode/encoder/byte_matrix.rs @@ -0,0 +1,112 @@ +/* + * Copyright 2008 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; + +/** + * JAVAPORT: The original code was a 2D array of ints, but since it only ever gets assigned + * -1, 0, and 1, I'm going to use less memory and go with bytes. + * + * @author dswitkin@google.com (Daniel Switkin) + */ +#[derive(Debug, PartialEq, Eq, Clone)] +pub struct ByteMatrix { + bytes: Vec>, + width: u32, + height: u32, +} + +impl ByteMatrix { + pub fn new(width: u32, height: u32) -> Self { + Self { + bytes: vec![vec![0u8; width as usize]; height as usize], + width, + height, + } + // bytes = new byte[height][width]; + } + + pub fn getHeight(&self) -> u32 { + self.height + } + + pub fn getWidth(&self) -> u32 { + self.width + } + + pub fn get(&self, x: u32, y: u32) -> u8 { + self.bytes[y as usize][x as usize] + } + + /** + * @return an internal representation as bytes, in row-major order. array[y][x] represents point (x,y) + */ + pub fn getArray(&self) -> &Vec> { + &self.bytes + } + + pub fn set(&mut self, x: u32, y: u32, value: u8) { + self.bytes[y as usize][x as usize] = value; + } + + // pub fn set(int x, int y, int value) { + // bytes[y][x] = (byte) value; + // } + + pub fn set_bool(&mut self, x: u32, y: u32, value: bool) { + self.bytes[y as usize][x as usize] = if value { 1 } else { 0 }; + } + + pub fn clear(&mut self, value: u8) { + for row in self.bytes.iter_mut() { + *row = vec![value; row.len()]; + } + // for (byte[] aByte : bytes) { + // Arrays.fill(aByte, value); + // } + } +} + +impl fmt::Display for ByteMatrix { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let mut result = String::with_capacity(2 * self.width as usize * self.height as usize + 2); + for y in 0..self.height as usize { + // for (int y = 0; y < height; ++y) { + let bytesY = &self.bytes[y]; + for x in 0..self.width as usize { + // for (int x = 0; x < width; ++x) { + match bytesY[x] { + 0 => result.push_str(" 0"), + 1 => result.push_str(" 1"), + _ => result.push_str(" "), + }; + // switch (bytesY[x]) { + // case 0: + // result.append(" 0"); + // break; + // case 1: + // result.append(" 1"); + // break; + // default: + // result.append(" "); + // break; + // } + } + result.push('\n'); + } + write!(f, "{}", result) + } +} diff --git a/src/qrcode/encoder/mod.rs b/src/qrcode/encoder/mod.rs index fa574a4..bb13369 100644 --- a/src/qrcode/encoder/mod.rs +++ b/src/qrcode/encoder/mod.rs @@ -1,3 +1,8 @@ mod qr_code; +mod byte_matrix; -pub use qr_code::*; \ No newline at end of file +pub use qr_code::*; +pub use byte_matrix::*; + +#[cfg(test)] +mod QRCodeTestCase; \ No newline at end of file diff --git a/src/qrcode/encoder/qr_code.rs b/src/qrcode/encoder/qr_code.rs index c3b319a..f036562 100644 --- a/src/qrcode/encoder/qr_code.rs +++ b/src/qrcode/encoder/qr_code.rs @@ -14,9 +14,13 @@ * limitations under the License. */ +use std::fmt; + use crate::qrcode::decoder::{Mode, ErrorCorrectionLevel, Version}; - const NUM_MASK_PATTERNS : u32 = 8; +use super::ByteMatrix; + + const NUM_MASK_PATTERNS : i32 = 8; /** * @author satorux@google.com (Satoru Takabayashi) - creator @@ -26,87 +30,97 @@ pub struct QRCode { // public static final int NUM_MASK_PATTERNS = 8; - mode:Mode, - ecLevel:ErrorCorrectionLevel, - version:Version, + mode:Option, + ecLevel:Option, + version:Option<&'static Version>, maskPattern:i32, - matrix:ByteMatrix, + matrix:Option, } impl QRCode { pub fn new()->Self { - maskPattern = -1; + Self { + mode: None, + ecLevel: None, + version: None, + maskPattern: -1, + matrix: None, + } } /** * @return the mode. Not relevant if {@link com.google.zxing.EncodeHintType#QR_COMPACT} is selected. */ - public Mode getMode() { - return mode; + pub fn getMode(&self) -> &Option{ + &self.mode } - public ErrorCorrectionLevel getECLevel() { - return ecLevel; + pub fn getECLevel(&self) -> &Option{ + &self.ecLevel } - public Version getVersion() { - return version; + pub fn getVersion(&self) -> &Option<&'static Version>{ + &self.version } - public int getMaskPattern() { - return maskPattern; + pub fn getMaskPattern(&self) -> i32{ + self.maskPattern } - public ByteMatrix getMatrix() { - return matrix; + pub fn getMatrix(&self) ->&Option{ + &self.matrix } - @Override - public String toString() { - StringBuilder result = new StringBuilder(200); - result.append("<<\n"); - result.append(" mode: "); - result.append(mode); - result.append("\n ecLevel: "); - result.append(ecLevel); - result.append("\n version: "); - result.append(version); - result.append("\n maskPattern: "); - result.append(maskPattern); - if (matrix == null) { - result.append("\n matrix: null\n"); - } else { - result.append("\n matrix:\n"); - result.append(matrix); - } - result.append(">>\n"); - return result.toString(); + + + pub fn setMode(&mut self, value:Mode) { + self.mode = Some(value); } - public void setMode(Mode value) { - mode = value; + pub fn setECLevel(&mut self, value:ErrorCorrectionLevel) { + self.ecLevel = Some(value); } - public void setECLevel(ErrorCorrectionLevel value) { - ecLevel = value; + pub fn setVersion(&mut self, version:&'static Version) { + self.version = Some(version); } - public void setVersion(Version version) { - this.version = version; + pub fn setMaskPattern(&mut self, value:i32) { + self.maskPattern = value; } - public void setMaskPattern(int value) { - maskPattern = value; - } - - public void setMatrix(ByteMatrix value) { - matrix = value; + pub fn setMatrix(&mut self, value:ByteMatrix) { + self.matrix = Some(value); } // Check if "mask_pattern" is valid. - public static boolean isValidMaskPattern(int maskPattern) { - return maskPattern >= 0 && maskPattern < NUM_MASK_PATTERNS; + pub fn isValidMaskPattern( maskPattern:i32) -> bool{ + maskPattern >= 0 && maskPattern < NUM_MASK_PATTERNS } } + +impl fmt::Display for QRCode { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let mut result = String::with_capacity(200); + result.push_str("<<\n"); + result.push_str(" mode: "); + result.push_str(&format!("{:?}", self.mode)); + result.push_str("\n ecLevel: "); + result.push_str(&format!("{:?}", self.ecLevel)); + result.push_str("\n version: "); + result.push_str(&format!("{}",self.version.as_ref().unwrap())); + result.push_str("\n maskPattern: "); + result.push_str(&format!("{}",self.maskPattern)); + if self.matrix.is_none() { + result.push_str("\n matrix: null\n"); + } else { + result.push_str("\n matrix:\n"); + result.push_str(&format!("{}",self.matrix.as_ref().unwrap())); + } + result.push_str(">>\n"); + + write!(f, "{}", result) + } +} \ No newline at end of file