mirror of
https://github.com/zxing/zxing.git
synced 2025-02-02 05:41:08 -08:00
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:
parent
d8b1011324
commit
6dbf893cb0
|
@ -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++) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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()));
|
||||
}
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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('.');
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in a new issue