diff --git a/src/lib.rs b/src/lib.rs
index d237686..c9973e4 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -962,13 +962,13 @@ pub enum RXingResultMetadataValue {
* If the code format supports structured append and the current scanned code is part of one then the
* sequence number is given with it.
*/
- StructuredAppendSequence(u32),
+ StructuredAppendSequence(i32),
/**
* If the code format supports structured append and the current scanned code is part of one then the
* parity is given with it.
*/
- StructuredAppendParity(u32),
+ StructuredAppendParity(i32),
/**
* Barcode Symbology Identifier.
diff --git a/src/qrcode/QRCodeReader.java b/src/qrcode/QRCodeReader.java
deleted file mode 100644
index 9165266..0000000
--- a/src/qrcode/QRCodeReader.java
+++ /dev/null
@@ -1,221 +0,0 @@
-/*
- * Copyright 2007 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;
-
-import com.google.zxing.BarcodeFormat;
-import com.google.zxing.BinaryBitmap;
-import com.google.zxing.ChecksumException;
-import com.google.zxing.DecodeHintType;
-import com.google.zxing.FormatException;
-import com.google.zxing.NotFoundException;
-import com.google.zxing.Reader;
-import com.google.zxing.RXingResult;
-import com.google.zxing.RXingResultMetadataType;
-import com.google.zxing.RXingResultPoint;
-import com.google.zxing.common.BitMatrix;
-import com.google.zxing.common.DecoderRXingResult;
-import com.google.zxing.common.DetectorRXingResult;
-import com.google.zxing.qrcode.decoder.Decoder;
-import com.google.zxing.qrcode.decoder.QRCodeDecoderMetaData;
-import com.google.zxing.qrcode.detector.Detector;
-
-import java.util.List;
-import java.util.Map;
-
-/**
- * This implementation can detect and decode QR Codes in an image.
- *
- * @author Sean Owen
- */
-public class QRCodeReader implements Reader {
-
- private static final RXingResultPoint[] NO_POINTS = new RXingResultPoint[0];
-
- private final Decoder decoder = new Decoder();
-
- protected final Decoder getDecoder() {
- return decoder;
- }
-
- /**
- * Locates and decodes a QR code in an image.
- *
- * @return a String representing the content encoded by the QR code
- * @throws NotFoundException if a QR code cannot be found
- * @throws FormatException if a QR code cannot be decoded
- * @throws ChecksumException if error correction fails
- */
- @Override
- public RXingResult decode(BinaryBitmap image) throws NotFoundException, ChecksumException, FormatException {
- return decode(image, null);
- }
-
- @Override
- public final RXingResult decode(BinaryBitmap image, Map hints)
- throws NotFoundException, ChecksumException, FormatException {
- DecoderRXingResult decoderRXingResult;
- RXingResultPoint[] points;
- if (hints != null && hints.containsKey(DecodeHintType.PURE_BARCODE)) {
- BitMatrix bits = extractPureBits(image.getBlackMatrix());
- decoderRXingResult = decoder.decode(bits, hints);
- points = NO_POINTS;
- } else {
- DetectorRXingResult detectorRXingResult = new Detector(image.getBlackMatrix()).detect(hints);
- decoderRXingResult = decoder.decode(detectorRXingResult.getBits(), hints);
- points = detectorRXingResult.getPoints();
- }
-
- // If the code was mirrored: swap the bottom-left and the top-right points.
- if (decoderRXingResult.getOther() instanceof QRCodeDecoderMetaData) {
- ((QRCodeDecoderMetaData) decoderRXingResult.getOther()).applyMirroredCorrection(points);
- }
-
- RXingResult result = new RXingResult(decoderRXingResult.getText(), decoderRXingResult.getRawBytes(), points, BarcodeFormat.QR_CODE);
- List byteSegments = decoderRXingResult.getByteSegments();
- if (byteSegments != null) {
- result.putMetadata(RXingResultMetadataType.BYTE_SEGMENTS, byteSegments);
- }
- String ecLevel = decoderRXingResult.getECLevel();
- if (ecLevel != null) {
- result.putMetadata(RXingResultMetadataType.ERROR_CORRECTION_LEVEL, ecLevel);
- }
- if (decoderRXingResult.hasStructuredAppend()) {
- result.putMetadata(RXingResultMetadataType.STRUCTURED_APPEND_SEQUENCE,
- decoderRXingResult.getStructuredAppendSequenceNumber());
- result.putMetadata(RXingResultMetadataType.STRUCTURED_APPEND_PARITY,
- decoderRXingResult.getStructuredAppendParity());
- }
- result.putMetadata(RXingResultMetadataType.SYMBOLOGY_IDENTIFIER, "]Q" + decoderRXingResult.getSymbologyModifier());
- return result;
- }
-
- @Override
- public void reset() {
- // do nothing
- }
-
- /**
- * This method detects a code in a "pure" image -- that is, pure monochrome image
- * which contains only an unrotated, unskewed, image of a code, with some white border
- * around it. This is a specialized method that works exceptionally fast in this special
- * case.
- */
- private static BitMatrix extractPureBits(BitMatrix image) throws NotFoundException {
-
- int[] leftTopBlack = image.getTopLeftOnBit();
- int[] rightBottomBlack = image.getBottomRightOnBit();
- if (leftTopBlack == null || rightBottomBlack == null) {
- throw NotFoundException.getNotFoundInstance();
- }
-
- float moduleSize = moduleSize(leftTopBlack, image);
-
- int top = leftTopBlack[1];
- int bottom = rightBottomBlack[1];
- int left = leftTopBlack[0];
- int right = rightBottomBlack[0];
-
- // Sanity check!
- if (left >= right || top >= bottom) {
- throw NotFoundException.getNotFoundInstance();
- }
-
- if (bottom - top != right - left) {
- // Special case, where bottom-right module wasn't black so we found something else in the last row
- // Assume it's a square, so use height as the width
- right = left + (bottom - top);
- if (right >= image.getWidth()) {
- // Abort if that would not make sense -- off image
- throw NotFoundException.getNotFoundInstance();
- }
- }
-
- int matrixWidth = Math.round((right - left + 1) / moduleSize);
- int matrixHeight = Math.round((bottom - top + 1) / moduleSize);
- if (matrixWidth <= 0 || matrixHeight <= 0) {
- throw NotFoundException.getNotFoundInstance();
- }
- if (matrixHeight != matrixWidth) {
- // Only possibly decode square regions
- throw NotFoundException.getNotFoundInstance();
- }
-
- // Push in the "border" by half the module width so that we start
- // sampling in the middle of the module. Just in case the image is a
- // little off, this will help recover.
- int nudge = (int) (moduleSize / 2.0f);
- top += nudge;
- left += nudge;
-
- // But careful that this does not sample off the edge
- // "right" is the farthest-right valid pixel location -- right+1 is not necessarily
- // This is positive by how much the inner x loop below would be too large
- int nudgedTooFarRight = left + (int) ((matrixWidth - 1) * moduleSize) - right;
- if (nudgedTooFarRight > 0) {
- if (nudgedTooFarRight > nudge) {
- // Neither way fits; abort
- throw NotFoundException.getNotFoundInstance();
- }
- left -= nudgedTooFarRight;
- }
- // See logic above
- int nudgedTooFarDown = top + (int) ((matrixHeight - 1) * moduleSize) - bottom;
- if (nudgedTooFarDown > 0) {
- if (nudgedTooFarDown > nudge) {
- // Neither way fits; abort
- throw NotFoundException.getNotFoundInstance();
- }
- top -= nudgedTooFarDown;
- }
-
- // Now just read off the bits
- BitMatrix bits = new BitMatrix(matrixWidth, matrixHeight);
- for (int y = 0; y < matrixHeight; y++) {
- int iOffset = top + (int) (y * moduleSize);
- for (int x = 0; x < matrixWidth; x++) {
- if (image.get(left + (int) (x * moduleSize), iOffset)) {
- bits.set(x, y);
- }
- }
- }
- return bits;
- }
-
- private static float moduleSize(int[] leftTopBlack, BitMatrix image) throws NotFoundException {
- int height = image.getHeight();
- int width = image.getWidth();
- int x = leftTopBlack[0];
- int y = leftTopBlack[1];
- boolean inBlack = true;
- int transitions = 0;
- while (x < width && y < height) {
- if (inBlack != image.get(x, y)) {
- if (++transitions == 5) {
- break;
- }
- inBlack = !inBlack;
- }
- x++;
- y++;
- }
- if (x == width || y == height) {
- throw NotFoundException.getNotFoundInstance();
- }
- return (x - leftTopBlack[0]) / 7.0f;
- }
-
-}
diff --git a/src/qrcode/QRCodeWriter.java b/src/qrcode/QRCodeWriter.java
deleted file mode 100644
index 50fccc6..0000000
--- a/src/qrcode/QRCodeWriter.java
+++ /dev/null
@@ -1,118 +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;
-
-import com.google.zxing.BarcodeFormat;
-import com.google.zxing.EncodeHintType;
-import com.google.zxing.Writer;
-import com.google.zxing.WriterException;
-import com.google.zxing.common.BitMatrix;
-import com.google.zxing.qrcode.encoder.ByteMatrix;
-import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
-import com.google.zxing.qrcode.encoder.Encoder;
-import com.google.zxing.qrcode.encoder.QRCode;
-
-import java.util.Map;
-
-/**
- * This object renders a QR Code as a BitMatrix 2D array of greyscale values.
- *
- * @author dswitkin@google.com (Daniel Switkin)
- */
-public final class QRCodeWriter implements Writer {
-
- private static final int QUIET_ZONE_SIZE = 4;
-
- @Override
- public BitMatrix encode(String contents, BarcodeFormat format, int width, int height)
- throws WriterException {
-
- return encode(contents, format, width, height, null);
- }
-
- @Override
- public BitMatrix encode(String contents,
- BarcodeFormat format,
- int width,
- int height,
- Map hints) throws WriterException {
-
- if (contents.isEmpty()) {
- throw new IllegalArgumentException("Found empty contents");
- }
-
- if (format != BarcodeFormat.QR_CODE) {
- throw new IllegalArgumentException("Can only encode QR_CODE, but got " + format);
- }
-
- if (width < 0 || height < 0) {
- throw new IllegalArgumentException("Requested dimensions are too small: " + width + 'x' +
- height);
- }
-
- ErrorCorrectionLevel errorCorrectionLevel = ErrorCorrectionLevel.L;
- int quietZone = QUIET_ZONE_SIZE;
- if (hints != null) {
- if (hints.containsKey(EncodeHintType.ERROR_CORRECTION)) {
- errorCorrectionLevel = ErrorCorrectionLevel.valueOf(hints.get(EncodeHintType.ERROR_CORRECTION).toString());
- }
- if (hints.containsKey(EncodeHintType.MARGIN)) {
- quietZone = Integer.parseInt(hints.get(EncodeHintType.MARGIN).toString());
- }
- }
-
- QRCode code = Encoder.encode(contents, errorCorrectionLevel, hints);
- return renderRXingResult(code, width, height, quietZone);
- }
-
- // Note that the input matrix uses 0 == white, 1 == black, while the output matrix uses
- // 0 == black, 255 == white (i.e. an 8 bit greyscale bitmap).
- private static BitMatrix renderRXingResult(QRCode code, int width, int height, int quietZone) {
- ByteMatrix input = code.getMatrix();
- if (input == null) {
- throw new IllegalStateException();
- }
- int inputWidth = input.getWidth();
- int inputHeight = input.getHeight();
- int qrWidth = inputWidth + (quietZone * 2);
- int qrHeight = inputHeight + (quietZone * 2);
- int outputWidth = Math.max(width, qrWidth);
- int outputHeight = Math.max(height, qrHeight);
-
- int multiple = Math.min(outputWidth / qrWidth, outputHeight / qrHeight);
- // Padding includes both the quiet zone and the extra white pixels to accommodate the requested
- // dimensions. For example, if input is 25x25 the QR will be 33x33 including the quiet zone.
- // If the requested size is 200x160, the multiple will be 4, for a QR of 132x132. These will
- // handle all the padding from 100x100 (the actual QR) up to 200x160.
- int leftPadding = (outputWidth - (inputWidth * multiple)) / 2;
- int topPadding = (outputHeight - (inputHeight * multiple)) / 2;
-
- BitMatrix output = new BitMatrix(outputWidth, outputHeight);
-
- for (int inputY = 0, outputY = topPadding; inputY < inputHeight; inputY++, outputY += multiple) {
- // Write the contents of this row of the barcode
- for (int inputX = 0, outputX = leftPadding; inputX < inputWidth; inputX++, outputX += multiple) {
- if (input.get(inputX, inputY) == 1) {
- output.setRegion(outputX, outputY, multiple, multiple);
- }
- }
- }
-
- return output;
- }
-
-}
diff --git a/src/qrcode/QRCodeWriterTestCase.java b/src/qrcode/QRCodeWriterTestCase.java
deleted file mode 100644
index 5a5abbc..0000000
--- a/src/qrcode/QRCodeWriterTestCase.java
+++ /dev/null
@@ -1,136 +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;
-
-import com.google.zxing.BarcodeFormat;
-import com.google.zxing.EncodeHintType;
-import com.google.zxing.Writer;
-import com.google.zxing.WriterException;
-import com.google.zxing.common.BitMatrix;
-import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
-import org.junit.Assert;
-import org.junit.Test;
-
-import javax.imageio.ImageIO;
-import java.awt.image.BufferedImage;
-import java.io.IOException;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.util.EnumMap;
-import java.util.Map;
-
-/**
- * @author satorux@google.com (Satoru Takabayashi) - creator
- * @author dswitkin@google.com (Daniel Switkin) - ported and expanded from C++
- */
-public final class QRCodeWriterTestCase extends Assert {
-
- private static final Path BASE_IMAGE_PATH = Paths.get("src/test/resources/golden/qrcode/");
-
- private static BufferedImage loadImage(String fileName) throws IOException {
- Path file = BASE_IMAGE_PATH.resolve(fileName);
- if (!Files.exists(file)) {
- // try starting with 'core' since the test base is often given as the project root
- file = Paths.get("core/").resolve(BASE_IMAGE_PATH).resolve(fileName);
- }
- assertTrue("Please download and install test images, and run from the 'core' directory", Files.exists(file));
- return ImageIO.read(file.toFile());
- }
-
- // In case the golden images are not monochromatic, convert the RGB values to greyscale.
- private static BitMatrix createMatrixFromImage(BufferedImage image) {
- int width = image.getWidth();
- int height = image.getHeight();
- int[] pixels = new int[width * height];
- image.getRGB(0, 0, width, height, pixels, 0, width);
-
- BitMatrix matrix = new BitMatrix(width, height);
- for (int y = 0; y < height; y++) {
- for (int x = 0; x < width; x++) {
- int pixel = pixels[y * width + x];
- int luminance = (306 * ((pixel >> 16) & 0xFF) +
- 601 * ((pixel >> 8) & 0xFF) +
- 117 * (pixel & 0xFF)) >> 10;
- if (luminance <= 0x7F) {
- matrix.set(x, y);
- }
- }
- }
- return matrix;
- }
-
- @Test
- public void testQRCodeWriter() throws WriterException {
- // The QR should be multiplied up to fit, with extra padding if necessary
- int bigEnough = 256;
- Writer writer = new QRCodeWriter();
- BitMatrix matrix = writer.encode("http://www.google.com/", BarcodeFormat.QR_CODE, bigEnough,
- bigEnough, null);
- assertNotNull(matrix);
- assertEquals(bigEnough, matrix.getWidth());
- assertEquals(bigEnough, matrix.getHeight());
-
- // The QR will not fit in this size, so the matrix should come back bigger
- int tooSmall = 20;
- matrix = writer.encode("http://www.google.com/", BarcodeFormat.QR_CODE, tooSmall,
- tooSmall, null);
- assertNotNull(matrix);
- assertTrue(tooSmall < matrix.getWidth());
- assertTrue(tooSmall < matrix.getHeight());
-
- // We should also be able to handle non-square requests by padding them
- int strangeWidth = 500;
- int strangeHeight = 100;
- matrix = writer.encode("http://www.google.com/", BarcodeFormat.QR_CODE, strangeWidth,
- strangeHeight, null);
- assertNotNull(matrix);
- assertEquals(strangeWidth, matrix.getWidth());
- assertEquals(strangeHeight, matrix.getHeight());
- }
-
- private static void compareToGoldenFile(String contents,
- ErrorCorrectionLevel ecLevel,
- int resolution,
- String fileName) throws WriterException, IOException {
-
- BufferedImage image = loadImage(fileName);
- assertNotNull(image);
- BitMatrix goldenRXingResult = createMatrixFromImage(image);
- assertNotNull(goldenRXingResult);
-
- Map hints = new EnumMap<>(EncodeHintType.class);
- hints.put(EncodeHintType.ERROR_CORRECTION, ecLevel);
- Writer writer = new QRCodeWriter();
- BitMatrix generatedRXingResult = writer.encode(contents, BarcodeFormat.QR_CODE, resolution,
- resolution, hints);
-
- assertEquals(resolution, generatedRXingResult.getWidth());
- assertEquals(resolution, generatedRXingResult.getHeight());
- assertEquals(goldenRXingResult, generatedRXingResult);
- }
-
- // Golden images are generated with "qrcode_sample.cc". The images are checked with both eye balls
- // and cell phones. We expect pixel-perfect results, because the error correction level is known,
- // and the pixel dimensions matches exactly.
- @Test
- public void testRegressionTest() throws Exception {
- compareToGoldenFile("http://www.google.com/", ErrorCorrectionLevel.M, 99,
- "renderer-test-01.png");
- }
-
-}
diff --git a/src/qrcode/QRCodeWriterTestCase.rs b/src/qrcode/QRCodeWriterTestCase.rs
new file mode 100644
index 0000000..1cebfab
--- /dev/null
+++ b/src/qrcode/QRCodeWriterTestCase.rs
@@ -0,0 +1,162 @@
+/*
+ * 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::{collections::HashMap, hash::Hash, path::{Path, PathBuf}};
+
+use image::{DynamicImage, EncodableLayout};
+
+use crate::{
+ common::BitMatrix, qrcode::QRCodeWriter, BarcodeFormat, EncodeHintType, EncodeHintValue, Writer,
+};
+
+use super::decoder::ErrorCorrectionLevel;
+
+/**
+ * @author satorux@google.com (Satoru Takabayashi) - creator
+ * @author dswitkin@google.com (Daniel Switkin) - ported and expanded from C++
+ */
+
+const BASE_IMAGE_PATH: &str = "test_resources/golden/qrcode/";
+
+fn loadImage(fileName: &str) -> DynamicImage {
+ let mut file = PathBuf::from(BASE_IMAGE_PATH);
+ file.push(fileName);
+ if !file.exists() {
+ // try starting with 'core' since the test base is often given as the project root
+ file = PathBuf::from("core/");
+ file.push(BASE_IMAGE_PATH);
+ file.push(fileName); //Paths.get("core/").resolve(BASE_IMAGE_PATH).resolve(fileName);
+ }
+ assert!(
+ file.exists(),
+ "Please download and install test images, and run from the 'core' directory"
+ );
+ DynamicImage::from(image::io::Reader::open(file).expect("image should load").decode().expect("decode"))
+}
+
+// In case the golden images are not monochromatic, convert the RGB values to greyscale.
+fn createMatrixFromImage(image: DynamicImage) -> BitMatrix {
+ let width = image.width() as usize;
+ let height = image.height() as usize;
+ // let pixels = vec![0u32; width * height]; //new int[width * height];
+ // image.getRGB(0, 0, width, height, pixels, 0, width);
+ let img_src = DynamicImage::from(image).into_rgb8();;//image.as_rgb8().unwrap().as_bytes();
+ let pixels = img_src.as_bytes();
+
+ let mut matrix = BitMatrix::new(width as u32, height as u32).expect("create new bitmatrix");
+ for y in 0..height {
+ // for (int y = 0; y < height; y++) {
+ for x in 0..width {
+ // for (int x = 0; x < width; x++) {
+ let pixel = pixels[y * width + x] as u32;
+ let luminance =
+ (306 * ((pixel >> 16) & 0xFF) + 601 * ((pixel >> 8) & 0xFF) + 117 * (pixel & 0xFF))
+ >> 10;
+ if (luminance <= 0x7F) {
+ matrix.set(x as u32, y as u32);
+ }
+ }
+ }
+ return matrix;
+}
+
+#[test]
+fn testQRCodeWriter() {
+ // The QR should be multiplied up to fit, with extra padding if necessary
+ let bigEnough = 256;
+ let writer = QRCodeWriter {};
+ let mut matrix = writer.encode_with_hints(
+ "http://www.google.com/",
+ &BarcodeFormat::QR_CODE,
+ bigEnough,
+ bigEnough,
+ &HashMap::new(),
+ );
+ assert!(matrix.is_ok());
+ let mut matrix = matrix.unwrap();
+ assert_eq!(bigEnough as u32, matrix.getWidth());
+ assert_eq!(bigEnough as u32, matrix.getHeight());
+
+ // The QR will not fit in this size, so the matrix should come back bigger
+ let tooSmall = 20;
+ matrix = writer.encode_with_hints(
+ "http://www.google.com/",
+ &BarcodeFormat::QR_CODE,
+ tooSmall,
+ tooSmall,
+ &HashMap::new(),
+ ).expect("should encode");
+ // assertNotNull(matrix);
+ assert!((tooSmall as u32) < matrix.getWidth());
+ assert!((tooSmall as u32) < matrix.getHeight());
+
+ // We should also be able to handle non-square requests by padding them
+ let strangeWidth = 500;
+ let strangeHeight = 100;
+ matrix = writer.encode_with_hints(
+ "http://www.google.com/",
+ &BarcodeFormat::QR_CODE,
+ strangeWidth,
+ strangeHeight,
+ &HashMap::new(),
+ ).expect("should encode");
+ // assertNotNull(matrix);
+ assert_eq!(strangeWidth as u32, matrix.getWidth());
+ assert_eq!(strangeHeight as u32, matrix.getHeight());
+}
+
+fn compareToGoldenFile(
+ contents: &str,
+ ecLevel: &ErrorCorrectionLevel,
+ resolution: u32,
+ fileName: &str,
+) {
+ let image = loadImage(fileName);
+ // assertNotNull(image);
+ let goldenRXingResult = createMatrixFromImage(image);
+ // assertNotNull(goldenRXingResult);
+
+ let mut hints = HashMap::new();
+ hints.insert(
+ EncodeHintType::ERROR_CORRECTION,
+ EncodeHintValue::ErrorCorrection(ecLevel.get_value().to_string()),
+ );
+ let writer = QRCodeWriter {};
+ let generatedRXingResult = writer.encode_with_hints(
+ contents,
+ &BarcodeFormat::QR_CODE,
+ resolution as i32,
+ resolution as i32,
+ &hints,
+ ).expect("should encode");
+
+ assert_eq!(resolution, generatedRXingResult.getWidth());
+ assert_eq!(resolution, generatedRXingResult.getHeight());
+ assert_eq!(goldenRXingResult, generatedRXingResult);
+}
+
+// Golden images are generated with "qrcode_sample.cc". The images are checked with both eye balls
+// and cell phones. We expect pixel-perfect results, because the error correction level is known,
+// and the pixel dimensions matches exactly.
+#[test]
+fn testRegressionTest() {
+ compareToGoldenFile(
+ "http://www.google.com/",
+ &ErrorCorrectionLevel::M,
+ 99,
+ "renderer-test-01.png",
+ );
+}
diff --git a/src/qrcode/decoder/bit_matrix_parser.rs b/src/qrcode/decoder/bit_matrix_parser.rs
index 2e4e325..575266c 100644
--- a/src/qrcode/decoder/bit_matrix_parser.rs
+++ b/src/qrcode/decoder/bit_matrix_parser.rs
@@ -82,7 +82,7 @@ impl BitMatrixParser {
let dimension = self.bitMatrix.getHeight();
let mut formatInfoBits2 = 0;
let jMin = dimension - 7;
- for j in (jMin..=dimension).rev() {
+ for j in (jMin..=dimension-1).rev() {
// for (int j = dimension - 1; j >= jMin; j--) {
formatInfoBits2 = self.copyBit(8, j, formatInfoBits2);
}
@@ -194,7 +194,7 @@ impl BitMatrixParser {
let mut currentByte = 0;
let mut bitsRead = 0;
// Read columns in pairs, from right to left
- let mut j = dimension - 1;
+ let mut j = dimension as i32 - 1;
while j > 0 {
// for (int j = dimension - 1; j > 0; j -= 2) {
if j == 6 {
@@ -213,11 +213,11 @@ impl BitMatrixParser {
for col in 0..2 {
// for (int col = 0; col < 2; col++) {
// Ignore bits covered by the function pattern
- if !functionPattern.get(j - col, i) {
+ if !functionPattern.get(j as u32 - col, i) {
// Read a bit
bitsRead += 1;
currentByte <<= 1;
- if self.bitMatrix.get(j - col, i) {
+ if self.bitMatrix.get(j as u32 - col, i) {
currentByte |= 1;
}
// If we've made a whole byte, save it off
diff --git a/src/qrcode/decoder/data_block.rs b/src/qrcode/decoder/data_block.rs
index c9fd416..3d01014 100755
--- a/src/qrcode/decoder/data_block.rs
+++ b/src/qrcode/decoder/data_block.rs
@@ -80,7 +80,8 @@ impl DataBlock {
// for (int i = 0; i < ecBlock.getCount(); i++) {
let numDataCodewords = ecBlock.getDataCodewords();
let numBlockCodewords = ecBlocks.getECCodewordsPerBlock() + numDataCodewords;
- result[numRXingResultBlocks] = DataBlock::new(numDataCodewords, vec![0u8;numBlockCodewords as usize]);
+ // result[numRXingResultBlocks] = DataBlock::new(numDataCodewords, vec![0u8;numBlockCodewords as usize]);
+ result.push( DataBlock::new(numDataCodewords, vec![0u8;numBlockCodewords as usize]));
numRXingResultBlocks += 1;
}
}
diff --git a/src/qrcode/decoder/error_correction_level.rs b/src/qrcode/decoder/error_correction_level.rs
index 908c8a5..6b30954 100644
--- a/src/qrcode/decoder/error_correction_level.rs
+++ b/src/qrcode/decoder/error_correction_level.rs
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+use std::str::FromStr;
+
use crate::Exceptions;
/**
@@ -85,6 +87,33 @@ impl From for u8 {
}
}
+impl FromStr for ErrorCorrectionLevel {
+ type Err=Exceptions;
+
+ fn from_str(s: &str) -> Result {
+ // First try to see if the string is just the name of the value
+ let as_str = match s.to_uppercase().as_str() {
+ "L" => Some(ErrorCorrectionLevel::L),
+ "M" => Some(ErrorCorrectionLevel::M),
+ "Q" =>Some(ErrorCorrectionLevel::Q),
+ "H" =>Some(ErrorCorrectionLevel::H),
+ _ => None,
+ };
+
+ // If we find something, cool, return it, otherwise keep trying as numbers
+ if as_str.is_some() {
+ return Ok(as_str.unwrap());
+ }
+
+ let number_possible = s.parse::();
+ if number_possible.is_ok() {
+ return number_possible.unwrap().try_into();
+ }
+
+ return Err(Exceptions::IllegalArgumentException(format!("could not parse {} into an ec level", s)))
+ }
+}
+
//private static final ErrorCorrectionLevel[] FOR_BITS = {M, L, H, Q};
//private final int bits;
diff --git a/src/qrcode/decoder/version.rs b/src/qrcode/decoder/version.rs
index 3ecdc50..de8bd38 100755
--- a/src/qrcode/decoder/version.rs
+++ b/src/qrcode/decoder/version.rs
@@ -45,6 +45,7 @@ const VERSION_DECODE_INFO: [u32; 34] = [
*
* @author Sean Owen
*/
+#[derive(Debug)]
pub struct Version {
// private static final Version[] VERSIONS = buildVersions();
versionNumber: u32,
@@ -930,7 +931,8 @@ impl fmt::Display for Version {
* each set of blocks. It also holds the number of error-correction codewords per block since it
* will be the same across all blocks within one version.
*/
-pub struct ECBlocks {
+#[derive(Debug)]
+ pub struct ECBlocks {
ecCodewordsPerBlock: u32,
ecBlocks: Vec,
}
@@ -970,6 +972,7 @@ impl ECBlocks {
* This includes the number of data codewords, and the number of times a block with these
* parameters is used consecutively in the QR code version's format.
*/
+#[derive(Debug)]
pub struct ECB {
count: u32,
dataCodewords: u32,
diff --git a/src/qrcode/detector/DetectorTest.rs b/src/qrcode/detector/DetectorTest.rs
new file mode 100644
index 0000000..3496574
--- /dev/null
+++ b/src/qrcode/detector/DetectorTest.rs
@@ -0,0 +1,62 @@
+use std::collections::HashMap;
+
+use crate::{qrcode::{
+ decoder::decoder, decoder::ErrorCorrectionLevel, detector::Detector, encoder::encoder,
+}, common::BitMatrix};
+
+#[test]
+fn test_simple() {
+ test_encode_decode("value");
+}
+
+#[test]
+fn test_uri() {
+ test_encode_decode("https://google.com");
+}
+
+#[test]
+fn test_unicode() {
+ test_encode_decode("\u{3484}\u{f8a7}\u{a1e7}");
+}
+
+fn test_encode_decode(value: &str) {
+ for ec_level_v in 0..4 {
+ let ec_level: ErrorCorrectionLevel =
+ ErrorCorrectionLevel::forBits(ec_level_v).expect("must get level");
+ let qr_code =
+ encoder::encode_with_hints(value, ec_level, &HashMap::new()).expect("must encode");
+ // dbg!(&qr_code.to_string());
+ let byt_matrix = qr_code.getMatrix().as_ref().unwrap().clone();
+ // dbg!(BitMatrix::from(byt_matrix.clone()).to_string());
+ // let mut detector = Detector::new(make_larger(&byt_matrix.into(),5));
+ let mut detector = Detector::new(byt_matrix.into());
+ let _detected_points = detector.detect().expect("must detect");
+ let decoded = decoder::decode_bitmatrix(
+ &qr_code
+ .getMatrix()
+ .clone()
+ .expect("matrix must exist")
+ .into(),
+ )
+ .expect("must decode");
+ assert_eq!(decoded.getText(), value);
+ }
+}
+
+// Zooms a bit matrix so that each bit is factor x factor
+fn make_larger(input: &BitMatrix, factor: u32) -> BitMatrix {
+ let width = input.getWidth();
+ let mut output = BitMatrix::with_single_dimension(width * factor);
+ for inputY in 0..width {
+ // for (int inputY = 0; inputY < width; inputY++) {
+ for inputX in 0..width {
+ // for (int inputX = 0; inputX < width; inputX++) {
+ if input.get(inputX, inputY) {
+ output
+ .setRegion(inputX * factor, inputY * factor, factor, factor)
+ .expect("region set should be ok");
+ }
+ }
+ }
+ return output;
+}
\ No newline at end of file
diff --git a/src/qrcode/detector/alignment_pattern_finder.rs b/src/qrcode/detector/alignment_pattern_finder.rs
index 290537e..1f26b3f 100644
--- a/src/qrcode/detector/alignment_pattern_finder.rs
+++ b/src/qrcode/detector/alignment_pattern_finder.rs
@@ -95,12 +95,12 @@ impl AlignmentPatternFinder {
for iGen in 0..height {
// for (int iGen = 0; iGen < height; iGen++) {
// Search from middle outwards
- let i = middleI
+ let i = (middleI as i32
+ (if (iGen & 0x01) == 0 {
- (iGen + 1) / 2
+ (iGen as i32 + 1) / 2
} else {
- -((iGen as i32 + 1) / 2) as u32
- });
+ -((iGen as i32 + 1) / 2)
+ })) as u32;
stateCount[0] = 0;
stateCount[1] = 0;
stateCount[2] = 0;
diff --git a/src/qrcode/detector/detector.rs b/src/qrcode/detector/detector.rs
index 6df5d54..71b6d87 100644
--- a/src/qrcode/detector/detector.rs
+++ b/src/qrcode/detector/detector.rs
@@ -336,27 +336,27 @@ impl Detector {
// Now count other way -- don't run off image though of course
let mut scale = 1.0;
- let mut otherToX = fromX - (toX - fromX);
+ let mut otherToX = fromX as i32 - (toX as i32 - fromX as i32);
if (otherToX < 0) {
- scale = fromX as f32 / (fromX - otherToX) as f32;
+ scale = fromX as f32 / (fromX as i32- otherToX) as f32;
otherToX = 0;
- } else if (otherToX >= self.image.getWidth()) {
- scale = (self.image.getWidth() - 1 - fromX) as f32 / (otherToX - fromX) as f32;
- otherToX = self.image.getWidth() - 1;
+ } else if (otherToX as u32 >= self.image.getWidth() ) {
+ scale = (self.image.getWidth() as i32 - 1 - fromX as i32) as f32 / (otherToX - fromX as i32) as f32;
+ otherToX = self.image.getWidth() as i32 - 1;
}
- let mut otherToY = (fromY - (toY - fromY) * scale as u32) as u32;
+ let mut otherToY = (fromY as i32 - (toY as i32 - fromY as i32) * scale as i32);
scale = 1.0;
if (otherToY < 0) {
- scale = fromY as f32 / (fromY - otherToY) as f32;
+ scale = fromY as f32 / (fromY as i32 - otherToY) as f32;
otherToY = 0;
- } else if (otherToY >= self.image.getHeight()) {
- scale = (self.image.getHeight() - 1 - fromY) as f32 / (otherToY - fromY) as f32;
- otherToY = self.image.getHeight() - 1;
+ } else if (otherToY as u32 >= self.image.getHeight()) {
+ scale = (self.image.getHeight() as i32 - 1 - fromY as i32) as f32 / (otherToY - fromY as i32) as f32;
+ otherToY = self.image.getHeight() as i32 - 1;
}
- otherToX = (fromX + (otherToX - fromX) * scale as u32) as u32;
+ otherToX = (fromX as i32+ (otherToX - fromX as i32) * scale as i32);
- result += self.sizeOfBlackWhiteBlackRun(fromX, fromY, otherToX, otherToY);
+ result += self.sizeOfBlackWhiteBlackRun(fromX as u32, fromY as u32, otherToX as u32, otherToY as u32);
// Middle pixel is double-counted this way; subtract 1
return result - 1.0;
@@ -377,7 +377,7 @@ impl Detector {
let mut toY = toY;
// Mild variant of Bresenham's algorithm;
// see http://en.wikipedia.org/wiki/Bresenham's_line_algorithm
- let steep = (toY - fromY) > (toX - fromX);
+ let steep = (toY as i64 - fromY as i64).abs() > (toX as i64 - fromX as i64).abs();
if (steep) {
let mut temp = fromX;
fromX = fromY;
@@ -387,8 +387,8 @@ impl Detector {
toY = temp;
}
- let dx: i32 = (toX - fromX) as i32;
- let dy: i32 = (toY - fromY) as i32;
+ let dx: i32 = (toX as i64 - fromX as i64).abs() as i32;
+ let dy: i32 = (toY as i64 - fromY as i64).abs() as i32;
let mut error = -dx / 2;
let xstep: i32 = if fromX < toX { 1 } else { -1 };
let ystep: i32 = if fromY < toY { 1 } else { -1 };
diff --git a/src/qrcode/detector/finder_pattern_finder.rs b/src/qrcode/detector/finder_pattern_finder.rs
index 77bc11b..1af1ef8 100755
--- a/src/qrcode/detector/finder_pattern_finder.rs
+++ b/src/qrcode/detector/finder_pattern_finder.rs
@@ -161,6 +161,7 @@ impl FinderPatternFinder {
stateCount[currentState] += 1;
}
}
+ j+=1;
}
if FinderPatternFinder::foundPatternCross(&stateCount) {
let confirmed = self.handlePossibleCenter(&stateCount, i, maxJ);
@@ -187,7 +188,7 @@ impl FinderPatternFinder {
* figures the location of the center of this run.
*/
fn centerFromEnd(stateCount: &[u32], end: u32) -> f32 {
- ((end - stateCount[4] - stateCount[3]) - stateCount[2]) as f32 / 2.0
+ (end - stateCount[4] - stateCount[3]) as f32 - ((stateCount[2] as f32) / 2.0)
}
/**
@@ -363,19 +364,19 @@ impl FinderPatternFinder {
) -> f32 {
// let image = &self.image;
- let maxI = self.image.getHeight();
+ let maxI = self.image.getHeight() as i32;
let _stateCount = self.getCrossCheckStateCount();
// Start counting up from center
- let mut i = startI;
- while i >= 0 && self.image.get(centerJ, i) {
+ let mut i = startI as i32;
+ while i >= 0 && self.image.get(centerJ, i as u32) {
self.crossCheckStateCount[2] += 1;
i -= 1;
}
if i < 0 {
return f32::NAN;
}
- while i >= 0 && !self.image.get(centerJ, i) && self.crossCheckStateCount[1] <= maxCount {
+ while i >= 0 && !self.image.get(centerJ, i as u32) && self.crossCheckStateCount[1] <= maxCount {
self.crossCheckStateCount[1] += 1;
i -= 1;
}
@@ -383,7 +384,7 @@ impl FinderPatternFinder {
if i < 0 || self.crossCheckStateCount[1] > maxCount {
return f32::NAN;
}
- while i >= 0 && self.image.get(centerJ, i) && self.crossCheckStateCount[0] <= maxCount {
+ while i >= 0 && self.image.get(centerJ, i as u32) && self.crossCheckStateCount[0] <= maxCount {
self.crossCheckStateCount[0] += 1;
i -= 1;
}
@@ -392,22 +393,22 @@ impl FinderPatternFinder {
}
// Now also count down from center
- i = startI + 1;
- while i < maxI && self.image.get(centerJ, i) {
+ i = startI as i32 + 1;
+ while i < maxI && self.image.get(centerJ, i as u32) {
self.crossCheckStateCount[2] += 1;
i += 1;
}
if i == maxI {
return f32::NAN;
}
- while i < maxI && !self.image.get(centerJ, i) && self.crossCheckStateCount[3] < maxCount {
+ while i < maxI && !self.image.get(centerJ, i as u32) && self.crossCheckStateCount[3] < maxCount {
self.crossCheckStateCount[3] += 1;
i += 1;
}
if i == maxI || self.crossCheckStateCount[3] >= maxCount {
return f32::NAN;
}
- while i < maxI && self.image.get(centerJ, i) && self.crossCheckStateCount[4] < maxCount {
+ while i < maxI && self.image.get(centerJ, i as u32) && self.crossCheckStateCount[4] < maxCount {
self.crossCheckStateCount[4] += 1;
i += 1;
}
@@ -422,12 +423,12 @@ impl FinderPatternFinder {
+ self.crossCheckStateCount[2]
+ self.crossCheckStateCount[3]
+ self.crossCheckStateCount[4];
- if 5 * (stateCountTotal - originalStateCountTotal) >= 2 * originalStateCountTotal {
+ if 5 * (stateCountTotal as i64 - originalStateCountTotal as i64) >= 2 * originalStateCountTotal as i64 {
return f32::NAN;
}
if Self::foundPatternCross(&self.crossCheckStateCount) {
- Self::centerFromEnd(&self.crossCheckStateCount, i)
+ Self::centerFromEnd(&self.crossCheckStateCount, i as u32)
} else {
f32::NAN
}
@@ -450,22 +451,22 @@ impl FinderPatternFinder {
let maxJ = self.image.getWidth();
let _stateCount = self.getCrossCheckStateCount();
- let mut j = startJ;
- while j >= 0 && self.image.get(j, centerI) {
+ let mut j = startJ as i32;
+ while j >= 0 && self.image.get(j as u32, centerI) {
self.crossCheckStateCount[2] += 1;
j -= 1;
}
if j < 0 {
return f32::NAN;
}
- while j >= 0 && !self.image.get(j, centerI) && self.crossCheckStateCount[1] <= maxCount {
+ while j >= 0 && !self.image.get(j as u32, centerI) && self.crossCheckStateCount[1] <= maxCount {
self.crossCheckStateCount[1] += 1;
j -= 1;
}
if j < 0 || self.crossCheckStateCount[1] > maxCount {
return f32::NAN;
}
- while j >= 0 && self.image.get(j, centerI) && self.crossCheckStateCount[0] <= maxCount {
+ while j >= 0 && self.image.get(j as u32 as u32, centerI) && self.crossCheckStateCount[0] <= maxCount {
self.crossCheckStateCount[0] += 1;
j -= 1;
}
@@ -473,22 +474,22 @@ impl FinderPatternFinder {
return f32::NAN;
}
- j = startJ + 1;
- while j < maxJ && self.image.get(j, centerI) {
+ j = startJ as i32 + 1;
+ while j < (maxJ as i32) && self.image.get(j as u32, centerI) {
self.crossCheckStateCount[2] += 1;
j += 1;
}
- if j == maxJ {
+ if j == maxJ as i32 {
return f32::NAN;
}
- while j < maxJ && !self.image.get(j, centerI) && self.crossCheckStateCount[3] < maxCount {
+ while j < maxJ as i32 && !self.image.get(j as u32, centerI) && self.crossCheckStateCount[3] < maxCount {
self.crossCheckStateCount[3] += 1;
j += 1;
}
- if j == maxJ || self.crossCheckStateCount[3] >= maxCount {
+ if j == (maxJ as i32) || self.crossCheckStateCount[3] >= maxCount {
return f32::NAN;
}
- while j < maxJ && self.image.get(j, centerI) && self.crossCheckStateCount[4] < maxCount {
+ while j < (maxJ as i32) && self.image.get(j as u32, centerI) && self.crossCheckStateCount[4] < maxCount {
self.crossCheckStateCount[4] += 1;
j += 1;
}
@@ -503,12 +504,12 @@ impl FinderPatternFinder {
+ self.crossCheckStateCount[2]
+ self.crossCheckStateCount[3]
+ self.crossCheckStateCount[4];
- if 5 * (stateCountTotal - originalStateCountTotal) >= originalStateCountTotal {
+ if 5 * (stateCountTotal as i64 - originalStateCountTotal as i64) >= originalStateCountTotal as i64 {
return f32::NAN;
}
if Self::foundPatternCross(&self.crossCheckStateCount) {
- Self::centerFromEnd(&self.crossCheckStateCount, j)
+ Self::centerFromEnd(&self.crossCheckStateCount, j as u32)
} else {
f32::NAN
}
diff --git a/src/qrcode/detector/mod.rs b/src/qrcode/detector/mod.rs
index f1cffd5..822363f 100644
--- a/src/qrcode/detector/mod.rs
+++ b/src/qrcode/detector/mod.rs
@@ -12,4 +12,7 @@ pub use alignment_pattern::*;
pub use alignment_pattern_finder::*;
pub use finder_pattern_finder::*;
pub use detector::*;
-pub use qrcode_detector_result::*;
\ No newline at end of file
+pub use qrcode_detector_result::*;
+
+#[cfg(test)]
+mod DetectorTest;
\ No newline at end of file
diff --git a/src/qrcode/encoder/byte_matrix.rs b/src/qrcode/encoder/byte_matrix.rs
index 4953136..2c3d43d 100644
--- a/src/qrcode/encoder/byte_matrix.rs
+++ b/src/qrcode/encoder/byte_matrix.rs
@@ -16,6 +16,8 @@
use std::fmt;
+use crate::common::BitMatrix;
+
/**
* 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.
@@ -110,3 +112,17 @@ impl fmt::Display for ByteMatrix {
write!(f, "{}", result)
}
}
+
+impl From for BitMatrix {
+ fn from(bm: ByteMatrix) -> Self {
+ let mut bit_matrix = BitMatrix::new(bm.getWidth(), bm.getHeight()).unwrap();
+ for y in 0..bm.getHeight() {
+ for x in 0..bm.getWidth() {
+ if bm.get(x, y) > 0 {
+ bit_matrix.set(x as u32, y as u32);
+ }
+ }
+ }
+ bit_matrix
+ }
+}
diff --git a/src/qrcode/encoder/qr_code.rs b/src/qrcode/encoder/qr_code.rs
index 0ecc1b2..00835c2 100644
--- a/src/qrcode/encoder/qr_code.rs
+++ b/src/qrcode/encoder/qr_code.rs
@@ -16,7 +16,7 @@
use std::fmt;
-use crate::qrcode::decoder::{Mode, ErrorCorrectionLevel, Version};
+use crate::qrcode::decoder::{Mode, ErrorCorrectionLevel, Version, VersionRef};
use super::ByteMatrix;
@@ -25,13 +25,14 @@ use super::ByteMatrix;
* @author satorux@google.com (Satoru Takabayashi) - creator
* @author dswitkin@google.com (Daniel Switkin) - ported from C++
*/
+#[derive(Debug, Clone)]
pub struct QRCode {
// public static final int NUM_MASK_PATTERNS = 8;
mode:Option,
ecLevel:Option,
- version:Option<&'static Version>,
+ version:Option,
maskPattern:i32,
matrix:Option,
diff --git a/src/qrcode/mod.rs b/src/qrcode/mod.rs
index 7964688..90ea2ca 100644
--- a/src/qrcode/mod.rs
+++ b/src/qrcode/mod.rs
@@ -1,3 +1,12 @@
pub mod detector;
pub mod decoder;
-pub mod encoder;
\ No newline at end of file
+pub mod encoder;
+
+mod qr_code_reader;
+pub use qr_code_reader::*;
+
+mod qr_code_writer;
+pub use qr_code_writer::*;
+
+#[cfg(test)]
+mod QRCodeWriterTestCase;
\ No newline at end of file
diff --git a/src/qrcode/qr_code_reader.rs b/src/qrcode/qr_code_reader.rs
new file mode 100644
index 0000000..8759290
--- /dev/null
+++ b/src/qrcode/qr_code_reader.rs
@@ -0,0 +1,252 @@
+/*
+ * Copyright 2007 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::collections::HashMap;
+
+use crate::{
+ common::{BitMatrix, DecoderRXingResult, DetectorRXingResult},
+ BarcodeFormat, DecodeHintType, Exceptions, RXingResult, RXingResultMetadataType,
+ RXingResultMetadataValue, RXingResultPoint, Reader, ResultPoint,
+};
+
+use super::{
+ decoder::{decoder, QRCodeDecoderMetaData},
+ detector::Detector,
+};
+
+/**
+ * This implementation can detect and decode QR Codes in an image.
+ *
+ * @author Sean Owen
+ */
+pub struct QRCodeReader;
+// pub struct QRCodeReader; {
+
+// // private static final RXingResultPoint[] NO_POINTS = new RXingResultPoint[0];
+// }
+
+impl Reader for QRCodeReader {
+ /**
+ * Locates and decodes a QR code in an image.
+ *
+ * @return a String representing the content encoded by the QR code
+ * @throws NotFoundException if a QR code cannot be found
+ * @throws FormatException if a QR code cannot be decoded
+ * @throws ChecksumException if error correction fails
+ */
+ fn decode(&self, image: &crate::BinaryBitmap) -> Result {
+ self.decode_with_hints(image, &HashMap::new())
+ }
+
+ fn decode_with_hints(
+ &self,
+ image: &crate::BinaryBitmap,
+ hints: &crate::DecodingHintDictionary,
+ ) -> Result {
+ let decoderRXingResult: DecoderRXingResult;
+ let mut points: Vec;
+ if hints.contains_key(&DecodeHintType::PURE_BARCODE) {
+ let bits = Self::extractPureBits(image.getBlackMatrix()?)?;
+ decoderRXingResult = decoder::decode_bitmatrix_with_hints(&bits, &hints)?;
+ points = Vec::new();
+ } else {
+ let detectorRXingResult =
+ Detector::new(image.getBlackMatrix()?.clone()).detect_with_hints(&hints)?;
+ decoderRXingResult =
+ decoder::decode_bitmatrix_with_hints(detectorRXingResult.getBits(), &hints)?;
+ points = detectorRXingResult.getPoints().clone();
+ }
+
+ // If the code was mirrored: swap the bottom-left and the top-right points.
+ if decoderRXingResult.getOther().is::() {
+ // if (decoderRXingResult.getOther() instanceof QRCodeDecoderMetaData) {
+ decoderRXingResult
+ .getOther()
+ .downcast_ref::()
+ .unwrap()
+ .applyMirroredCorrection(&mut points);
+ // ((QRCodeDecoderMetaData) decoderRXingResult.getOther()).applyMirroredCorrection(points);
+ }
+
+ let mut result = RXingResult::new(
+ decoderRXingResult.getText(),
+ decoderRXingResult.getRawBytes().clone(),
+ points,
+ BarcodeFormat::QR_CODE,
+ );
+ let byteSegments = decoderRXingResult.getByteSegments();
+ if !byteSegments.is_empty() {
+ result.putMetadata(
+ RXingResultMetadataType::BYTE_SEGMENTS,
+ RXingResultMetadataValue::ByteSegments(byteSegments.clone()),
+ );
+ }
+ let ecLevel = decoderRXingResult.getECLevel();
+ if !ecLevel.is_empty() {
+ result.putMetadata(
+ RXingResultMetadataType::ERROR_CORRECTION_LEVEL,
+ RXingResultMetadataValue::ErrorCorrectionLevel(ecLevel.to_owned()),
+ );
+ }
+ if decoderRXingResult.hasStructuredAppend() {
+ result.putMetadata(
+ RXingResultMetadataType::STRUCTURED_APPEND_SEQUENCE,
+ RXingResultMetadataValue::StructuredAppendSequence(
+ decoderRXingResult.getStructuredAppendSequenceNumber(),
+ ),
+ );
+ result.putMetadata(
+ RXingResultMetadataType::STRUCTURED_APPEND_PARITY,
+ RXingResultMetadataValue::StructuredAppendParity(
+ decoderRXingResult.getStructuredAppendParity(),
+ ),
+ );
+ }
+ result.putMetadata(
+ RXingResultMetadataType::SYMBOLOGY_IDENTIFIER,
+ RXingResultMetadataValue::SymbologyIdentifier(format!(
+ "]Q{}",
+ decoderRXingResult.getSymbologyModifier()
+ )),
+ );
+
+ Ok(result)
+ }
+
+ fn reset(&self) {
+ // nothing
+ }
+}
+
+impl QRCodeReader {
+ pub fn new() -> Self {
+ Self {}
+ }
+
+ /**
+ * This method detects a code in a "pure" image -- that is, pure monochrome image
+ * which contains only an unrotated, unskewed, image of a code, with some white border
+ * around it. This is a specialized method that works exceptionally fast in this special
+ * case.
+ */
+ fn extractPureBits(image: &BitMatrix) -> Result {
+ let leftTopBlack = image.getTopLeftOnBit();
+ let rightBottomBlack = image.getBottomRightOnBit();
+ if leftTopBlack.is_none() || rightBottomBlack.is_none() {
+ return Err(Exceptions::NotFoundException("".to_owned()));
+ }
+
+ let leftTopBlack = leftTopBlack.unwrap();
+ let rightBottomBlack = rightBottomBlack.unwrap();
+
+ let moduleSize = Self::moduleSize(&leftTopBlack, image)?;
+
+ let mut top = leftTopBlack[1] as i32;
+ let mut bottom = rightBottomBlack[1] as i32;
+ let mut left = leftTopBlack[0] as i32;
+ let mut right = rightBottomBlack[0] as i32;
+
+ // Sanity check!
+ if left >= right || top >= bottom {
+ return Err(Exceptions::NotFoundException("".to_owned()));
+ }
+
+ if bottom - top != right - left {
+ // Special case, where bottom-right module wasn't black so we found something else in the last row
+ // Assume it's a square, so use height as the width
+ right = left + (bottom - top);
+ if right >= image.getWidth() as i32 {
+ // Abort if that would not make sense -- off image
+ return Err(Exceptions::NotFoundException("".to_owned()));
+ }
+ }
+ let matrixWidth = ((right as f32 - left as f32 + 1.0) / moduleSize).round() as u32;
+ let matrixHeight = ((bottom as f32 - top as f32 + 1.0) / moduleSize).round() as u32;
+ if matrixWidth <= 0 || matrixHeight <= 0 {
+ return Err(Exceptions::NotFoundException("".to_owned()));
+ }
+ if matrixHeight != matrixWidth {
+ // Only possibly decode square regions
+ return Err(Exceptions::NotFoundException("".to_owned()));
+ }
+
+ // Push in the "border" by half the module width so that we start
+ // sampling in the middle of the module. Just in case the image is a
+ // little off, this will help recover.
+ let nudge = (moduleSize / 2.0) as u32;
+ top += nudge as i32;
+ left += nudge as i32;
+
+ // But careful that this does not sample off the edge
+ // "right" is the farthest-right valid pixel location -- right+1 is not necessarily
+ // This is positive by how much the inner x loop below would be too large
+ let nudgedTooFarRight = left as i32 + ((matrixWidth as i32 - 1) as f32 * moduleSize as f32) as i32 - right as i32;
+ if nudgedTooFarRight > 0 {
+ if nudgedTooFarRight > nudge as i32 {
+ // Neither way fits; abort
+ return Err(Exceptions::NotFoundException("".to_owned()));
+ }
+ left -= nudgedTooFarRight;
+ }
+ // See logic above
+ let nudgedTooFarDown = top + ((matrixHeight - 1) as f32 * moduleSize) as i32 - bottom;
+ if nudgedTooFarDown > 0 {
+ if nudgedTooFarDown > nudge as i32 {
+ // Neither way fits; abort
+ return Err(Exceptions::NotFoundException("".to_owned()));
+ }
+ top -= nudgedTooFarDown;
+ }
+
+ // Now just read off the bits
+ let mut bits = BitMatrix::new(matrixWidth, matrixHeight)?;
+ for y in 0..matrixHeight {
+ // for (int y = 0; y < matrixHeight; y++) {
+ let iOffset = top + ((y as f32) * moduleSize) as i32;
+ for x in 0..matrixWidth {
+ // for (int x = 0; x < matrixWidth; x++) {
+ if image.get(left as u32 + (x as f32 * moduleSize) as u32, iOffset as u32) {
+ bits.set(x, y);
+ }
+ }
+ }
+ Ok(bits)
+ }
+
+ fn moduleSize(leftTopBlack: &[u32], image: &BitMatrix) -> Result {
+ let height = image.getHeight();
+ let width = image.getWidth();
+ let mut x = leftTopBlack[0];
+ let mut y = leftTopBlack[1];
+ let mut inBlack = true;
+ let mut transitions = 0;
+ while x < width && y < height {
+ if inBlack != image.get(x, y) {
+ transitions += 1;
+ if transitions == 5 {
+ break;
+ }
+ inBlack = !inBlack;
+ }
+ x += 1;
+ y += 1;
+ }
+ if x == width || y == height {
+ return Err(Exceptions::NotFoundException("".to_owned()));
+ }
+ Ok((x - leftTopBlack[0]) as f32 / 7.0)
+ }
+}
diff --git a/src/qrcode/qr_code_writer.rs b/src/qrcode/qr_code_writer.rs
new file mode 100644
index 0000000..5e31473
--- /dev/null
+++ b/src/qrcode/qr_code_writer.rs
@@ -0,0 +1,174 @@
+/*
+ * 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::collections::HashMap;
+
+use crate::{
+ common::BitMatrix, BarcodeFormat, EncodeHintType, EncodeHintValue, Exceptions, Writer,
+};
+
+use super::{
+ decoder::ErrorCorrectionLevel,
+ encoder::{encoder, QRCode},
+};
+
+const QUIET_ZONE_SIZE: i32 = 4;
+
+/**
+ * This object renders a QR Code as a BitMatrix 2D array of greyscale values.
+ *
+ * @author dswitkin@google.com (Daniel Switkin)
+ */
+pub struct QRCodeWriter; // {
+
+// private static final int QUIET_ZONE_SIZE = 4;
+//}
+
+impl Writer for QRCodeWriter {
+ fn encode(
+ &self,
+ contents: &str,
+ format: &crate::BarcodeFormat,
+ width: i32,
+ height: i32,
+ ) -> Result {
+ self.encode_with_hints(contents, format, width, height, &HashMap::new())
+ }
+
+ fn encode_with_hints(
+ &self,
+ contents: &str,
+ format: &crate::BarcodeFormat,
+ width: i32,
+ height: i32,
+ hints: &crate::EncodingHintDictionary,
+ ) -> Result {
+ if (contents.is_empty()) {
+ return Err(Exceptions::IllegalArgumentException(
+ "Found empty contents".to_owned(),
+ ));
+ // throw new IllegalArgumentException("Found empty contents");
+ }
+
+ if format != &BarcodeFormat::QR_CODE {
+ return Err(Exceptions::IllegalArgumentException(format!(
+ "Can only encode QR_CODE, but got {:?}",
+ format
+ )));
+ // throw new IllegalArgumentException("Can only encode QR_CODE, but got " + format);
+ }
+
+ if (width < 0 || height < 0) {
+ return Err(Exceptions::IllegalArgumentException(format!(
+ "Requested dimensions are too small: {}x{}",
+ width, height
+ )));
+ // throw new IllegalArgumentException("Requested dimensions are too small: " + width + 'x' +
+ // height);
+ }
+
+ let mut errorCorrectionLevel = ErrorCorrectionLevel::L;
+ let mut quietZone = QUIET_ZONE_SIZE;
+ // if (hints != null) {
+ if hints.contains_key(&EncodeHintType::ERROR_CORRECTION) {
+ if let EncodeHintValue::ErrorCorrection(ec_level) =
+ hints.get(&EncodeHintType::ERROR_CORRECTION).unwrap()
+ {
+ errorCorrectionLevel = ec_level.parse()?;
+ }
+ // errorCorrectionLevel = ErrorCorrectionLevel.valueOf(hints.get(EncodeHintType.ERROR_CORRECTION).toString());
+ }
+ if hints.contains_key(&EncodeHintType::MARGIN) {
+ if let EncodeHintValue::Margin(margin) = hints.get(&EncodeHintType::MARGIN).unwrap() {
+ quietZone = margin.parse().unwrap();
+ // quietZone = Integer.parseInt(hints.get(EncodeHintType.MARGIN).toString());
+ }
+
+ // quietZone = Integer.parseInt(hints.get(EncodeHintType.MARGIN).toString());
+ }
+ // }
+
+ let code = encoder::encode_with_hints(contents, errorCorrectionLevel, &hints)?;
+
+ Self::renderRXingResult(&code, width, height, quietZone)
+ }
+}
+
+impl QRCodeWriter {
+ // Note that the input matrix uses 0 == white, 1 == black, while the output matrix uses
+ // 0 == black, 255 == white (i.e. an 8 bit greyscale bitmap).
+ fn renderRXingResult(
+ code: &QRCode,
+ width: i32,
+ height: i32,
+ quietZone: i32,
+ ) -> Result {
+ let input = code.getMatrix();
+ if input.is_none() {
+ return Err(Exceptions::IllegalStateException(
+ "matrix is empty".to_owned(),
+ ));
+ // throw new IllegalStateException();
+ }
+
+ let input = input.as_ref().unwrap();
+
+ let inputWidth = input.getWidth() as i32;
+ let inputHeight = input.getHeight() as i32;
+ let qrWidth = inputWidth + (quietZone * 2);
+ let qrHeight = inputHeight + (quietZone * 2);
+ let outputWidth = width.max(qrWidth);
+ let outputHeight = height.max(qrHeight);
+
+ let multiple = (outputWidth / qrWidth).min(outputHeight / qrHeight);
+ // Padding includes both the quiet zone and the extra white pixels to accommodate the requested
+ // dimensions. For example, if input is 25x25 the QR will be 33x33 including the quiet zone.
+ // If the requested size is 200x160, the multiple will be 4, for a QR of 132x132. These will
+ // handle all the padding from 100x100 (the actual QR) up to 200x160.
+ let leftPadding = (outputWidth - (inputWidth * multiple)) / 2;
+ let topPadding = (outputHeight - (inputHeight * multiple)) / 2;
+
+ let mut output = BitMatrix::new(outputWidth as u32, outputHeight as u32)?;
+
+ let mut inputY = 0;
+ let mut outputY = topPadding;
+ while inputY < inputHeight {
+ // for (int inputY = 0, outputY = topPadding; inputY < inputHeight; inputY++, outputY += multiple) {
+ // Write the contents of this row of the barcode
+ let mut inputX = 0;
+ let mut outputX = leftPadding;
+ while inputX < inputWidth {
+ // for (int inputX = 0, outputX = leftPadding; inputX < inputWidth; inputX++, outputX += multiple) {
+ if input.get(inputX as u32, inputY as u32) == 1 {
+ output.setRegion(
+ outputX as u32,
+ outputY as u32,
+ multiple as u32,
+ multiple as u32,
+ );
+ }
+
+ inputX += 1;
+ outputX += multiple;
+ }
+
+ inputY += 1;
+ outputY += multiple;
+ }
+
+ Ok(output)
+ }
+}
diff --git a/tests/QRCodeBlackBox1TestCase.java b/tests/QRCodeBlackBox1TestCase.rs
similarity index 54%
rename from tests/QRCodeBlackBox1TestCase.java
rename to tests/QRCodeBlackBox1TestCase.rs
index 805db74..0f28c1e 100644
--- a/tests/QRCodeBlackBox1TestCase.java
+++ b/tests/QRCodeBlackBox1TestCase.rs
@@ -14,23 +14,26 @@
* limitations under the License.
*/
-package com.google.zxing.qrcode;
+use rxing::qrcode::QRCodeReader;
-import com.google.zxing.BarcodeFormat;
-import com.google.zxing.MultiFormatReader;
-import com.google.zxing.common.AbstractBlackBoxTestCase;
+mod common;
/**
* @author Sean Owen
*/
-public final class QRCodeBlackBox1TestCase extends AbstractBlackBoxTestCase {
- public QRCodeBlackBox1TestCase() {
- super("src/test/resources/blackbox/qrcode-1", new MultiFormatReader(), BarcodeFormat.QR_CODE);
- addTest(17, 17, 0.0f);
- addTest(14, 14, 90.0f);
- addTest(17, 17, 180.0f);
- addTest(14, 14, 270.0f);
- }
+#[test]
+fn QRCodeBlackBox1TestCase() {
+ let mut tester = common::AbstractBlackBoxTestCase::new(
+ "test_resources/blackbox/qrcode-1",
+ Box::new(QRCodeReader {}),
+ rxing::BarcodeFormat::QR_CODE,
+ );
+ // super("src/test/resources/blackbox/qrcode-1", new MultiFormatReader(), BarcodeFormat.QR_CODE);
+ tester.addTest(17, 17, 0.0);
+ tester.addTest(14, 14, 90.0);
+ tester.addTest(17, 17, 180.0);
+ tester.addTest(14, 14, 270.0);
+ tester.testBlackBox();
}
diff --git a/tests/QRCodeBlackBox2TestCase.java b/tests/QRCodeBlackBox2TestCase.rs
similarity index 55%
rename from tests/QRCodeBlackBox2TestCase.java
rename to tests/QRCodeBlackBox2TestCase.rs
index 7c11dad..e674924 100644
--- a/tests/QRCodeBlackBox2TestCase.java
+++ b/tests/QRCodeBlackBox2TestCase.rs
@@ -14,23 +14,22 @@
* limitations under the License.
*/
-package com.google.zxing.qrcode;
+use rxing::{qrcode::QRCodeReader, BarcodeFormat};
-import com.google.zxing.BarcodeFormat;
-import com.google.zxing.MultiFormatReader;
-import com.google.zxing.common.AbstractBlackBoxTestCase;
+mod common;
/**
* @author Sean Owen
*/
-public final class QRCodeBlackBox2TestCase extends AbstractBlackBoxTestCase {
- public QRCodeBlackBox2TestCase() {
- super("src/test/resources/blackbox/qrcode-2", new MultiFormatReader(), BarcodeFormat.QR_CODE);
- addTest(31, 31, 0.0f);
- addTest(30, 30, 90.0f);
- addTest(30, 30, 180.0f);
- addTest(30, 30, 270.0f);
+ #[test]
+ fn QRCodeBlackBox2TestCase() {
+ let mut tester = common::AbstractBlackBoxTestCase::new("test_resources/blackbox/qrcode-2", Box::new(QRCodeReader{}), BarcodeFormat::QR_CODE);
+ tester.addTest(31, 31, 0.0);
+ tester.addTest(30, 30, 90.0);
+ tester.addTest(30, 30, 180.0);
+ tester.addTest(30, 30, 270.0);
+
+ tester.testBlackBox();
}
-}
diff --git a/tests/QRCodeBlackBox3TestCase.java b/tests/QRCodeBlackBox3TestCase.rs
similarity index 56%
rename from tests/QRCodeBlackBox3TestCase.java
rename to tests/QRCodeBlackBox3TestCase.rs
index 9968608..ddf9d9e 100644
--- a/tests/QRCodeBlackBox3TestCase.java
+++ b/tests/QRCodeBlackBox3TestCase.rs
@@ -14,23 +14,22 @@
* limitations under the License.
*/
-package com.google.zxing.qrcode;
+use rxing::{qrcode::QRCodeReader, BarcodeFormat};
-import com.google.zxing.BarcodeFormat;
-import com.google.zxing.MultiFormatReader;
-import com.google.zxing.common.AbstractBlackBoxTestCase;
+mod common;
/**
* @author dswitkin@google.com (Daniel Switkin)
*/
-public final class QRCodeBlackBox3TestCase extends AbstractBlackBoxTestCase {
- public QRCodeBlackBox3TestCase() {
- super("src/test/resources/blackbox/qrcode-3", new MultiFormatReader(), BarcodeFormat.QR_CODE);
- addTest(38, 38, 0.0f);
- addTest(39, 39, 90.0f);
- addTest(36, 36, 180.0f);
- addTest(39, 39, 270.0f);
+#[test]
+fn QRCodeBlackBox3TestCase() {
+ let mut tester = common::AbstractBlackBoxTestCase::new("test_resources/blackbox/qrcode-3", Box::new(QRCodeReader{}), BarcodeFormat::QR_CODE);
+ tester.addTest(38, 38, 0.0);
+ tester.addTest(39, 39, 90.0);
+ tester.addTest(36, 36, 180.0);
+ tester.addTest(39, 39, 270.0);
+
+ tester.testBlackBox();
}
-}
diff --git a/tests/QRCodeBlackBox4TestCase.java b/tests/QRCodeBlackBox4TestCase.rs
similarity index 59%
rename from tests/QRCodeBlackBox4TestCase.java
rename to tests/QRCodeBlackBox4TestCase.rs
index 8693aff..55df756 100644
--- a/tests/QRCodeBlackBox4TestCase.java
+++ b/tests/QRCodeBlackBox4TestCase.rs
@@ -14,25 +14,24 @@
* limitations under the License.
*/
-package com.google.zxing.qrcode;
+use rxing::{qrcode::QRCodeReader, BarcodeFormat};
-import com.google.zxing.BarcodeFormat;
-import com.google.zxing.MultiFormatReader;
-import com.google.zxing.common.AbstractBlackBoxTestCase;
+mod common;
/**
* Tests of various QR Codes from t-shirts, which are notoriously not flat.
*
* @author dswitkin@google.com (Daniel Switkin)
*/
-public final class QRCodeBlackBox4TestCase extends AbstractBlackBoxTestCase {
- public QRCodeBlackBox4TestCase() {
- super("src/test/resources/blackbox/qrcode-4", new MultiFormatReader(), BarcodeFormat.QR_CODE);
- addTest(36, 36, 0.0f);
- addTest(35, 35, 90.0f);
- addTest(35, 35, 180.0f);
- addTest(35, 35, 270.0f);
+#[test]
+fn QRCodeBlackBox4TestCase() {
+ let mut tester = common::AbstractBlackBoxTestCase::new("test_resources/blackbox/qrcode-4", Box::new(QRCodeReader{}), BarcodeFormat::QR_CODE);
+ tester.addTest(36, 36, 0.0);
+ tester.addTest(35, 35, 90.0);
+ tester.addTest(35, 35, 180.0);
+ tester.addTest(35, 35, 270.0);
+
+ tester.testBlackBox();
}
-}
diff --git a/tests/QRCodeBlackBox5TestCase.java b/tests/QRCodeBlackBox5TestCase.rs
similarity index 64%
rename from tests/QRCodeBlackBox5TestCase.java
rename to tests/QRCodeBlackBox5TestCase.rs
index 404bc45..01332f6 100644
--- a/tests/QRCodeBlackBox5TestCase.java
+++ b/tests/QRCodeBlackBox5TestCase.rs
@@ -14,11 +14,9 @@
* limitations under the License.
*/
-package com.google.zxing.qrcode;
+use rxing::{BarcodeFormat, qrcode::QRCodeReader};
-import com.google.zxing.BarcodeFormat;
-import com.google.zxing.MultiFormatReader;
-import com.google.zxing.common.AbstractBlackBoxTestCase;
+mod common;
/**
* Some very difficult exposure conditions including self-shadowing, which happens a lot when
@@ -27,14 +25,15 @@ import com.google.zxing.common.AbstractBlackBoxTestCase;
*
* @author dswitkin@google.com (Daniel Switkin)
*/
-public final class QRCodeBlackBox5TestCase extends AbstractBlackBoxTestCase {
- public QRCodeBlackBox5TestCase() {
- super("src/test/resources/blackbox/qrcode-5", new MultiFormatReader(), BarcodeFormat.QR_CODE);
- addTest(19, 19, 0.0f);
- addTest(19, 19, 90.0f);
- addTest(19, 19, 180.0f);
- addTest(19, 19, 270.0f);
+#[test]
+fn QRCodeBlackBox5TestCase() {
+ let mut tester = common::AbstractBlackBoxTestCase::new("test_resources/blackbox/qrcode-5", Box::new(QRCodeReader{}), BarcodeFormat::QR_CODE);
+ tester.addTest(19, 19, 0.0);
+ tester.addTest(19, 19, 90.0);
+ tester.addTest(19, 19, 180.0);
+ tester.addTest(19, 19, 270.0);
+
+ tester.testBlackBox();
}
-}
diff --git a/tests/QRCodeBlackBox6TestCase.java b/tests/QRCodeBlackBox6TestCase.rs
similarity index 59%
rename from tests/QRCodeBlackBox6TestCase.java
rename to tests/QRCodeBlackBox6TestCase.rs
index 531ffa6..cbfcec4 100644
--- a/tests/QRCodeBlackBox6TestCase.java
+++ b/tests/QRCodeBlackBox6TestCase.rs
@@ -14,24 +14,22 @@
* limitations under the License.
*/
-package com.google.zxing.qrcode;
+use rxing::{qrcode::QRCodeReader, BarcodeFormat};
-import com.google.zxing.BarcodeFormat;
-import com.google.zxing.MultiFormatReader;
-import com.google.zxing.common.AbstractBlackBoxTestCase;
+mod common;
/**
* These tests are supplied by Tim Gernat and test finder pattern detection at small size and under
* rotation, which was a weak spot.
*/
-public final class QRCodeBlackBox6TestCase extends AbstractBlackBoxTestCase {
- public QRCodeBlackBox6TestCase() {
- super("src/test/resources/blackbox/qrcode-6", new MultiFormatReader(), BarcodeFormat.QR_CODE);
- addTest(15, 15, 0.0f);
- addTest(14, 14, 90.0f);
- addTest(13, 13, 180.0f);
- addTest(14, 14, 270.0f);
+#[test]
+fn QRCodeBlackBox6TestCase() {
+ let mut tester = common::AbstractBlackBoxTestCase::new("test_resources/blackbox/qrcode-6", Box::new(QRCodeReader{}), BarcodeFormat::QR_CODE);
+ tester.addTest(15, 15, 0.0);
+ tester.addTest(14, 14, 90.0);
+ tester.addTest(13, 13, 180.0);
+ tester.addTest(14, 14, 270.0);
+
+ tester.testBlackBox();
}
-
-}
diff --git a/tests/common/abstract_black_box_test_case.rs b/tests/common/abstract_black_box_test_case.rs
index 157fbb3..1919556 100644
--- a/tests/common/abstract_black_box_test_case.rs
+++ b/tests/common/abstract_black_box_test_case.rs
@@ -189,7 +189,7 @@ impl AbstractBlackBoxTestCase {
RXingResultMetadataValue::Orientation(v.parse().unwrap_or_default())
}
RXingResultMetadataType::BYTE_SEGMENTS => {
- RXingResultMetadataValue::ByteSegments(v.into_bytes())
+ RXingResultMetadataValue::ByteSegments(vec![v.into_bytes()])
}
RXingResultMetadataType::ERROR_CORRECTION_LEVEL => {
RXingResultMetadataValue::ErrorCorrectionLevel(v)