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
This commit is contained in:
srowen 2009-07-30 08:58:57 +00:00
parent d8b1011324
commit 6dbf893cb0
12 changed files with 154 additions and 51 deletions

View file

@ -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++) {

View file

@ -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;
}

View file

@ -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);

View file

@ -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) {

View file

@ -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);
}

View file

@ -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.

View file

@ -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()));
}

View file

@ -57,6 +57,7 @@ public final class BufferedImageLuminanceSource extends LuminanceSource {
// These methods use an integer calculation for luminance derived from:
// <code>Y = 0.299R + 0.587G + 0.114B</code>
@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");

View file

@ -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('.');

View file

@ -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;
/**
* <p>Simple GUI frontend to the library. Right now, only decodes a local file.

View file

@ -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);

View file

@ -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);
}
}