From 6dbf893cb0323530559c0c62a84d5bcd81640169 Mon Sep 17 00:00:00 2001 From: srowen Date: Thu, 30 Jul 2009 08:58:57 +0000 Subject: [PATCH] Add MatrixToImageWriter convenience class, small code tweaks in javase/, make ByteMatrix width/height property getters names standard git-svn-id: https://zxing.googlecode.com/svn/trunk@1028 59b500cc-1b3d-0410-9834-0bbf25fbcc57 --- .../zxing/client/android/QRCodeEncoder.java | 4 +- .../com/google/zxing/common/ByteMatrix.java | 4 +- .../com/google/zxing/qrcode/QRCodeWriter.java | 4 +- .../google/zxing/qrcode/encoder/MaskUtil.java | 18 ++-- .../zxing/qrcode/encoder/MatrixUtil.java | 32 +++---- .../google/zxing/qrcode/encoder/QRCode.java | 4 +- .../zxing/qrcode/QRCodeWriterTestCase.java | 20 ++--- .../j2se/BufferedImageLuminanceSource.java | 6 ++ .../zxing/client/j2se/CommandLineRunner.java | 5 +- .../google/zxing/client/j2se/GUIRunner.java | 12 ++- .../zxing/client/j2se/ImageConverter.java | 7 +- .../client/j2se/MatrixToImageWriter.java | 89 +++++++++++++++++++ 12 files changed, 154 insertions(+), 51 deletions(-) create mode 100644 javase/src/com/google/zxing/client/j2se/MatrixToImageWriter.java diff --git a/android/src/com/google/zxing/client/android/QRCodeEncoder.java b/android/src/com/google/zxing/client/android/QRCodeEncoder.java index 434301c5e..a66155250 100755 --- a/android/src/com/google/zxing/client/android/QRCodeEncoder.java +++ b/android/src/com/google/zxing/client/android/QRCodeEncoder.java @@ -214,8 +214,8 @@ public final class QRCodeEncoder { try { ByteMatrix result = new MultiFormatWriter().encode(mContents, mFormat, mPixelResolution, mPixelResolution); - int width = result.width(); - int height = result.height(); + int width = result.getWidth(); + int height = result.getHeight(); byte[][] array = result.getArray(); int[] pixels = new int[width * height]; for (int y = 0; y < height; y++) { diff --git a/core/src/com/google/zxing/common/ByteMatrix.java b/core/src/com/google/zxing/common/ByteMatrix.java index 2c801ae75..9ac01bc6f 100644 --- a/core/src/com/google/zxing/common/ByteMatrix.java +++ b/core/src/com/google/zxing/common/ByteMatrix.java @@ -37,11 +37,11 @@ public final class ByteMatrix { this.height = height; } - public int height() { + public int getHeight() { return height; } - public int width() { + public int getWidth() { return width; } diff --git a/core/src/com/google/zxing/qrcode/QRCodeWriter.java b/core/src/com/google/zxing/qrcode/QRCodeWriter.java index 84ee4be1f..0c59ed7cf 100644 --- a/core/src/com/google/zxing/qrcode/QRCodeWriter.java +++ b/core/src/com/google/zxing/qrcode/QRCodeWriter.java @@ -75,8 +75,8 @@ public final class QRCodeWriter implements Writer { // 0 == black, 255 == white (i.e. an 8 bit greyscale bitmap). private static ByteMatrix renderResult(QRCode code, int width, int height) { ByteMatrix input = code.getMatrix(); - int inputWidth = input.width(); - int inputHeight = input.height(); + int inputWidth = input.getWidth(); + int inputHeight = input.getHeight(); int qrWidth = inputWidth + (QUIET_ZONE_SIZE << 1); int qrHeight = inputHeight + (QUIET_ZONE_SIZE << 1); int outputWidth = Math.max(width, qrWidth); diff --git a/core/src/com/google/zxing/qrcode/encoder/MaskUtil.java b/core/src/com/google/zxing/qrcode/encoder/MaskUtil.java index 27fadef77..e4806e528 100644 --- a/core/src/com/google/zxing/qrcode/encoder/MaskUtil.java +++ b/core/src/com/google/zxing/qrcode/encoder/MaskUtil.java @@ -39,8 +39,8 @@ public final class MaskUtil { public static int applyMaskPenaltyRule2(ByteMatrix matrix) { int penalty = 0; byte[][] array = matrix.getArray(); - int width = matrix.width(); - int height = matrix.height(); + int width = matrix.getWidth(); + int height = matrix.getHeight(); for (int y = 0; y < height - 1; ++y) { for (int x = 0; x < width - 1; ++x) { int value = array[y][x]; @@ -58,8 +58,8 @@ public final class MaskUtil { public static int applyMaskPenaltyRule3(ByteMatrix matrix) { int penalty = 0; byte[][] array = matrix.getArray(); - int width = matrix.width(); - int height = matrix.height(); + int width = matrix.getWidth(); + int height = matrix.getHeight(); for (int y = 0; y < height; ++y) { for (int x = 0; x < width; ++x) { // Tried to simplify following conditions but failed. @@ -120,8 +120,8 @@ public final class MaskUtil { public static int applyMaskPenaltyRule4(ByteMatrix matrix) { int numDarkCells = 0; byte[][] array = matrix.getArray(); - int width = matrix.width(); - int height = matrix.height(); + int width = matrix.getWidth(); + int height = matrix.getHeight(); for (int y = 0; y < height; ++y) { for (int x = 0; x < width; ++x) { if (array[y][x] == 1) { @@ -129,7 +129,7 @@ public final class MaskUtil { } } } - int numTotalCells = matrix.height() * matrix.width(); + int numTotalCells = matrix.getHeight() * matrix.getWidth(); double darkRatio = (double) numDarkCells / numTotalCells; return Math.abs((int) (darkRatio * 100 - 50)) / 5 * 10; } @@ -189,8 +189,8 @@ public final class MaskUtil { // for (int i = 0; i < matrix.width(); ++i) { // for (int j = 0; j < matrix.height(); ++j) { // int bit = matrix.get(j, i); - int iLimit = isHorizontal ? matrix.height() : matrix.width(); - int jLimit = isHorizontal ? matrix.width() : matrix.height(); + int iLimit = isHorizontal ? matrix.getHeight() : matrix.getWidth(); + int jLimit = isHorizontal ? matrix.getWidth() : matrix.getHeight(); byte[][] array = matrix.getArray(); for (int i = 0; i < iLimit; ++i) { for (int j = 0; j < jLimit; ++j) { diff --git a/core/src/com/google/zxing/qrcode/encoder/MatrixUtil.java b/core/src/com/google/zxing/qrcode/encoder/MatrixUtil.java index 5409cdf0b..c4c007f2f 100644 --- a/core/src/com/google/zxing/qrcode/encoder/MatrixUtil.java +++ b/core/src/com/google/zxing/qrcode/encoder/MatrixUtil.java @@ -184,13 +184,13 @@ public final class MatrixUtil { if (i < 8) { // Right top corner. - int x2 = matrix.width() - i - 1; + int x2 = matrix.getWidth() - i - 1; int y2 = 8; matrix.set(x2, y2, bit); } else { // Left bottom corner. int x2 = 8; - int y2 = matrix.height() - 7 + (i - 8); + int y2 = matrix.getHeight() - 7 + (i - 8); matrix.set(x2, y2, bit); } } @@ -212,9 +212,9 @@ public final class MatrixUtil { int bit = versionInfoBits.at(bitIndex); bitIndex--; // Left bottom corner. - matrix.set(i, matrix.height() - 11 + j, bit); + matrix.set(i, matrix.getHeight() - 11 + j, bit); // Right bottom corner. - matrix.set(matrix.height() - 11 + j, i, bit); + matrix.set(matrix.getHeight() - 11 + j, i, bit); } } } @@ -227,14 +227,14 @@ public final class MatrixUtil { int bitIndex = 0; int direction = -1; // Start from the right bottom cell. - int x = matrix.width() - 1; - int y = matrix.height() - 1; + int x = matrix.getWidth() - 1; + int y = matrix.getHeight() - 1; while (x > 0) { // Skip the vertical timing pattern. if (x == 6) { x -= 1; } - while (y >= 0 && y < matrix.height()) { + while (y >= 0 && y < matrix.getHeight()) { for (int i = 0; i < 2; ++i) { int xx = x - i; // Skip the cell if it's not empty. @@ -373,7 +373,7 @@ public final class MatrixUtil { private static void embedTimingPatterns(ByteMatrix matrix) throws WriterException { // -8 is for skipping position detection patterns (size 7), and two horizontal/vertical // separation patterns (size 1). Thus, 8 = 7 + 1. - for (int i = 8; i < matrix.width() - 8; ++i) { + for (int i = 8; i < matrix.getWidth() - 8; ++i) { int bit = (i + 1) % 2; // Horizontal line. if (!isValidValue(matrix.get(i, 6))) { @@ -394,10 +394,10 @@ public final class MatrixUtil { // Embed the lonely dark dot at left bottom corner. JISX0510:2004 (p.46) private static void embedDarkDotAtLeftBottomCorner(ByteMatrix matrix) throws WriterException { - if (matrix.get(8, matrix.height() - 8) == 0) { + if (matrix.get(8, matrix.getHeight() - 8) == 0) { throw new WriterException(); } - matrix.set(8, matrix.height() - 8, 1); + matrix.set(8, matrix.getHeight() - 8, 1); } private static void embedHorizontalSeparationPattern(int xStart, int yStart, @@ -470,28 +470,28 @@ public final class MatrixUtil { // Left top corner. embedPositionDetectionPattern(0, 0, matrix); // Right top corner. - embedPositionDetectionPattern(matrix.width() - pdpWidth, 0, matrix); + embedPositionDetectionPattern(matrix.getWidth() - pdpWidth, 0, matrix); // Left bottom corner. - embedPositionDetectionPattern(0, matrix.width() - pdpWidth, matrix); + embedPositionDetectionPattern(0, matrix.getWidth() - pdpWidth, matrix); // Embed horizontal separation patterns around the squares. int hspWidth = HORIZONTAL_SEPARATION_PATTERN[0].length; // Left top corner. embedHorizontalSeparationPattern(0, hspWidth - 1, matrix); // Right top corner. - embedHorizontalSeparationPattern(matrix.width() - hspWidth, + embedHorizontalSeparationPattern(matrix.getWidth() - hspWidth, hspWidth - 1, matrix); // Left bottom corner. - embedHorizontalSeparationPattern(0, matrix.width() - hspWidth, matrix); + embedHorizontalSeparationPattern(0, matrix.getWidth() - hspWidth, matrix); // Embed vertical separation patterns around the squares. int vspSize = VERTICAL_SEPARATION_PATTERN.length; // Left top corner. embedVerticalSeparationPattern(vspSize, 0, matrix); // Right top corner. - embedVerticalSeparationPattern(matrix.height() - vspSize - 1, 0, matrix); + embedVerticalSeparationPattern(matrix.getHeight() - vspSize - 1, 0, matrix); // Left bottom corner. - embedVerticalSeparationPattern(vspSize, matrix.height() - vspSize, + embedVerticalSeparationPattern(vspSize, matrix.getHeight() - vspSize, matrix); } diff --git a/core/src/com/google/zxing/qrcode/encoder/QRCode.java b/core/src/com/google/zxing/qrcode/encoder/QRCode.java index 2340ee170..75ec9e72d 100644 --- a/core/src/com/google/zxing/qrcode/encoder/QRCode.java +++ b/core/src/com/google/zxing/qrcode/encoder/QRCode.java @@ -134,9 +134,9 @@ public final class QRCode { numTotalBytes == numDataBytes + numECBytes && // ByteMatrix stuff. matrix != null && - matrixWidth == matrix.width() && + matrixWidth == matrix.getWidth() && // See 7.3.1 of JISX0510:2004 (p.5). - matrix.width() == matrix.height(); // Must be square. + matrix.getWidth() == matrix.getHeight(); // Must be square. } // Return debug String. diff --git a/core/test/src/com/google/zxing/qrcode/QRCodeWriterTestCase.java b/core/test/src/com/google/zxing/qrcode/QRCodeWriterTestCase.java index 4e83df1da..e9ef9b1ac 100644 --- a/core/test/src/com/google/zxing/qrcode/QRCodeWriterTestCase.java +++ b/core/test/src/com/google/zxing/qrcode/QRCodeWriterTestCase.java @@ -79,16 +79,16 @@ public final class QRCodeWriterTestCase extends TestCase { ByteMatrix matrix = writer.encode("http://www.google.com/", BarcodeFormat.QR_CODE, bigEnough, bigEnough, null); assertNotNull(matrix); - assertEquals(bigEnough, matrix.width()); - assertEquals(bigEnough, matrix.height()); + 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.width()); - assertTrue(tooSmall < matrix.height()); + assertTrue(tooSmall < matrix.getWidth()); + assertTrue(tooSmall < matrix.getHeight()); // We should also be able to handle non-square requests by padding them int strangeWidth = 500; @@ -96,8 +96,8 @@ public final class QRCodeWriterTestCase extends TestCase { matrix = writer.encode("http://www.google.com/", BarcodeFormat.QR_CODE, strangeWidth, strangeHeight, null); assertNotNull(matrix); - assertEquals(strangeWidth, matrix.width()); - assertEquals(strangeHeight, matrix.height()); + assertEquals(strangeWidth, matrix.getWidth()); + assertEquals(strangeHeight, matrix.getHeight()); } private static void compareToGoldenFile(String contents, ErrorCorrectionLevel ecLevel, @@ -114,10 +114,10 @@ public final class QRCodeWriterTestCase extends TestCase { ByteMatrix generatedResult = writer.encode(contents, BarcodeFormat.QR_CODE, resolution, resolution, hints); - assertEquals("Width should be " + resolution + ", but was " + generatedResult.width(), - resolution, generatedResult.width()); - assertEquals("Height should be " + resolution + ", but was " + generatedResult.height(), - resolution, generatedResult.height()); + assertEquals("Width should be " + resolution + ", but was " + generatedResult.getWidth(), + resolution, generatedResult.getWidth()); + assertEquals("Height should be " + resolution + ", but was " + generatedResult.getHeight(), + resolution, generatedResult.getHeight()); assertTrue("Expected " + goldenResult.toString() + " but got " + generatedResult.toString(), Arrays.deepEquals(goldenResult.getArray(), generatedResult.getArray())); } diff --git a/javase/src/com/google/zxing/client/j2se/BufferedImageLuminanceSource.java b/javase/src/com/google/zxing/client/j2se/BufferedImageLuminanceSource.java index b251eb79c..e5d45b595 100644 --- a/javase/src/com/google/zxing/client/j2se/BufferedImageLuminanceSource.java +++ b/javase/src/com/google/zxing/client/j2se/BufferedImageLuminanceSource.java @@ -57,6 +57,7 @@ public final class BufferedImageLuminanceSource extends LuminanceSource { // These methods use an integer calculation for luminance derived from: // Y = 0.299R + 0.587G + 0.114B + @Override public byte[] getRow(int y, byte[] row) { if (y < 0 || y >= getHeight()) { throw new IllegalArgumentException("Requested row is outside the image: " + y); @@ -80,6 +81,7 @@ public final class BufferedImageLuminanceSource extends LuminanceSource { return row; } + @Override public byte[] getMatrix() { int width = getWidth(); int height = getHeight(); @@ -101,19 +103,23 @@ public final class BufferedImageLuminanceSource extends LuminanceSource { return matrix; } + @Override public boolean isCropSupported() { return true; } + @Override public LuminanceSource crop(int left, int top, int width, int height) { return new BufferedImageLuminanceSource(image, left, top, width, height); } // Can't run AffineTransforms on images of unknown format. + @Override public boolean isRotateSupported() { return image.getType() != BufferedImage.TYPE_CUSTOM; } + @Override public LuminanceSource rotateCounterClockwise() { if (!isRotateSupported()) { throw new IllegalStateException("Rotate not supported"); diff --git a/javase/src/com/google/zxing/client/j2se/CommandLineRunner.java b/javase/src/com/google/zxing/client/j2se/CommandLineRunner.java index 90d525c8c..5138e3a47 100644 --- a/javase/src/com/google/zxing/client/j2se/CommandLineRunner.java +++ b/javase/src/com/google/zxing/client/j2se/CommandLineRunner.java @@ -224,7 +224,6 @@ public final class CommandLineRunner { image.getRGB(0, y, width, 1, argb, 0, width); System.arraycopy(argb, 0, pixels, y * stride, width); } - argb = null; // Row sampling BitArray row = new BitArray(width); @@ -272,10 +271,10 @@ public final class CommandLineRunner { // Use the current working directory for URLs String resultName = inputName; - if (uri.getScheme().equals("http")) { + if ("http".equals(uri.getScheme())) { int pos = resultName.lastIndexOf('/'); if (pos > 0) { - resultName = "." + resultName.substring(pos); + resultName = '.' + resultName.substring(pos); } } int pos = resultName.lastIndexOf('.'); diff --git a/javase/src/com/google/zxing/client/j2se/GUIRunner.java b/javase/src/com/google/zxing/client/j2se/GUIRunner.java index 34322406d..9d26021cd 100644 --- a/javase/src/com/google/zxing/client/j2se/GUIRunner.java +++ b/javase/src/com/google/zxing/client/j2se/GUIRunner.java @@ -23,14 +23,22 @@ import com.google.zxing.ReaderException; import com.google.zxing.Result; import com.google.zxing.common.GlobalHistogramBinarizer; -import java.awt.*; +import java.awt.Container; +import java.awt.Dimension; +import java.awt.FlowLayout; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; import java.net.MalformedURLException; import javax.imageio.ImageIO; -import javax.swing.*; +import javax.swing.Icon; +import javax.swing.ImageIcon; +import javax.swing.JFileChooser; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JTextArea; /** *

Simple GUI frontend to the library. Right now, only decodes a local file. diff --git a/javase/src/com/google/zxing/client/j2se/ImageConverter.java b/javase/src/com/google/zxing/client/j2se/ImageConverter.java index 83aab9092..895424e74 100644 --- a/javase/src/com/google/zxing/client/j2se/ImageConverter.java +++ b/javase/src/com/google/zxing/client/j2se/ImageConverter.java @@ -55,9 +55,9 @@ public final class ImageConverter { public static void main(String[] args) throws Exception { for (String arg : args) { - if (arg.equals("-row")) { + if ("-row".equals(arg)) { rowSampling = true; - } else if (arg.equals("-2d")) { + } else if ("-2d".equals(arg)) { rowSampling = false; } else if (arg.startsWith("-")) { System.out.println("Ignoring unrecognized option: " + arg); @@ -140,7 +140,8 @@ public final class ImageConverter { private static File getFileOfUri(URI uri) { String name = uri.getPath(); int slashPos = name.lastIndexOf((int) '/'); - String parent, basename; + String parent; + String basename; if (slashPos != -1 && slashPos != name.length() - 1) { parent = name.substring(0, slashPos); basename = name.substring(slashPos + 1); diff --git a/javase/src/com/google/zxing/client/j2se/MatrixToImageWriter.java b/javase/src/com/google/zxing/client/j2se/MatrixToImageWriter.java new file mode 100644 index 000000000..e0dd71729 --- /dev/null +++ b/javase/src/com/google/zxing/client/j2se/MatrixToImageWriter.java @@ -0,0 +1,89 @@ +/* + * Copyright 2009 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.client.j2se; + +import com.google.zxing.common.BitMatrix; +import com.google.zxing.common.ByteMatrix; + +import javax.imageio.ImageIO; +import java.io.File; +import java.io.OutputStream; +import java.io.IOException; +import java.awt.image.BufferedImage; + +/** + * Writes a {@link BitMatrix} or {@link ByteMatrix} to {@link BufferedImage}, file or stream. + * Provided here instead of core since it depends on Java SE libraries. + * + * @author Sean Owen + */ +public final class MatrixToImageWriter { + + private static final int BLACK = 0x00000000; + private static final int WHITE = 0x00FFFFFF; + + private MatrixToImageWriter() {} + + public static BufferedImage toBufferedImage(BitMatrix matrix) { + int width = matrix.getWidth(); + int height = matrix.getHeight(); + BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); + for (int x = 0; x < width; x++) { + for (int y = 0; y < height; y++) { + image.setRGB(x, y, matrix.get(x, y) ? BLACK : WHITE); + } + } + return image; + } + + public static BufferedImage toBufferedImage(ByteMatrix matrix) { + int width = matrix.getWidth(); + int height = matrix.getHeight(); + BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); + for (int x = 0; x < width; x++) { + for (int y = 0; y < height; y++) { + image.setRGB(x, y, matrix.get(x, y) == 0 ? WHITE : BLACK); + } + } + return image; + } + + public static void writeToFile(BitMatrix matrix, String format, File file) + throws IOException { + BufferedImage image = toBufferedImage(matrix); + ImageIO.write(image, format, file); + } + + public static void writeToFile(ByteMatrix matrix, String format, File file) + throws IOException { + BufferedImage image = toBufferedImage(matrix); + ImageIO.write(image, format, file); + } + + public static void writeToStream(BitMatrix matrix, String format, OutputStream stream) + throws IOException { + BufferedImage image = toBufferedImage(matrix); + ImageIO.write(image, format, stream); + } + + public static void writeToStream(ByteMatrix matrix, String format, OutputStream stream) + throws IOException { + BufferedImage image = toBufferedImage(matrix); + ImageIO.write(image, format, stream); + } + +}