package com.google.zxing.client.android;
+import android.graphics.Matrix;
import com.google.zxing.MonochromeBitmapSource;
import com.google.zxing.ReaderException;
import com.google.zxing.common.BitMatrix;
-import com.google.zxing.qrcode.detector.AlignmentPattern;
-import com.google.zxing.qrcode.detector.FinderPattern;
-import com.google.zxing.qrcode.detector.GridSampler;
-
-import android.graphics.Matrix;
+import com.google.zxing.common.GridSampler;
/**
* Implementation based on Android's
public final class AndroidGraphicsGridSampler extends GridSampler {
@Override
- protected BitMatrix sampleGrid(MonochromeBitmapSource image,
- FinderPattern topLeft,
- FinderPattern topRight,
- FinderPattern bottomLeft,
- AlignmentPattern alignmentPattern,
- int dimension) throws ReaderException {
- float dimMinusThree = (float) dimension - 3.5f;
- float bottomRightX, bottomRightY;
- float sourceBottomRightX, sourceBottomRightY;
- if (alignmentPattern != null) {
- bottomRightX = alignmentPattern.getX();
- bottomRightY = alignmentPattern.getY();
- sourceBottomRightX = sourceBottomRightY = dimMinusThree - 3.0f;
- } else {
- // Don't have an alignment pattern, just make up the bottom-right point
- bottomRightX = (topRight.getX() - topLeft.getX()) + bottomLeft.getX();
- bottomRightY = (topRight.getY() - topLeft.getY()) + bottomLeft.getY();
- sourceBottomRightX = sourceBottomRightY = dimMinusThree;
- }
+ public BitMatrix sampleGrid(MonochromeBitmapSource image,
+ int dimension,
+ float p1ToX, float p1ToY,
+ float p2ToX, float p2ToY,
+ float p3ToX, float p3ToY,
+ float p4ToX, float p4ToY,
+ float p1FromX, float p1FromY,
+ float p2FromX, float p2FromY,
+ float p3FromX, float p3FromY,
+ float p4FromX, float p4FromY) throws ReaderException {
Matrix transformMatrix = new Matrix();
boolean succeeded = transformMatrix.setPolyToPoly(
- new float[] {
- topLeft.getX(),
- topLeft.getY(),
- topRight.getX(),
- topRight.getY(),
- bottomLeft.getX(),
- bottomLeft.getY(),
- bottomRightX,
- bottomRightY
- },
+ new float[] { p1FromX, p1FromY, p2FromX, p2FromY, p3FromX, p3FromY, p4FromX, p4FromY },
0,
- new float[] {
- 3.5f,
- 3.5f,
- dimMinusThree,
- 3.5f,
- 3.5f,
- dimMinusThree,
- sourceBottomRightX,
- sourceBottomRightY,
- },
+ new float[] { p1ToX, p1ToY, p2ToX, p2ToY, p3ToX, p3ToY, p4ToX, p4ToY },
0,
4
);
--- /dev/null
+/*
+ * Copyright 2007 Google Inc.
+ *
+ * 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.common;
+
+import com.google.zxing.MonochromeBitmapSource;
+import com.google.zxing.ReaderException;
+
+/**
+ * @author srowen@google.com (Sean Owen)
+ */
+public final class DefaultGridSampler extends GridSampler {
+
+ public BitMatrix sampleGrid(MonochromeBitmapSource image,
+ int dimension,
+ float p1ToX, float p1ToY,
+ float p2ToX, float p2ToY,
+ float p3ToX, float p3ToY,
+ float p4ToX, float p4ToY,
+ float p1FromX, float p1FromY,
+ float p2FromX, float p2FromY,
+ float p3FromX, float p3FromY,
+ float p4FromX, float p4FromY) throws ReaderException {
+
+ PerspectiveTransform transform = PerspectiveTransform.quadrilateralToQuadrilateral(
+ p1ToX, p1ToY, p2ToX, p2ToY, p3ToX, p3ToY, p4ToX, p4ToY,
+ p1FromX, p1FromY, p2FromX, p2FromY, p3FromX, p3FromY, p4FromX, p4FromY);
+
+ BitMatrix bits = new BitMatrix(dimension);
+ float[] points = new float[dimension << 1];
+ for (int i = 0; i < dimension; i++) {
+ int max = points.length;
+ float iValue = (float) i + 0.5f;
+ for (int j = 0; j < max; j += 2) {
+ points[j] = (float) (j >> 1) + 0.5f;
+ points[j + 1] = iValue;
+ }
+ transform.transformPoints(points);
+ // Quick check to see if points transformed to something inside the image;
+ // sufficent to check the endpoints
+ checkEndpoint(image, points);
+ for (int j = 0; j < max; j += 2) {
+ if (image.isBlack((int) points[j], (int) points[j + 1])) {
+ // Black(-ish) pixel
+ bits.set(i, j >> 1);
+ }
+ }
+ }
+ return bits;
+ }
+
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright 2007 Google Inc.
+ *
+ * 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.common;
+
+import com.google.zxing.MonochromeBitmapSource;
+import com.google.zxing.ReaderException;
+
+/**
+ * Implementations of this class can, given locations of finder patterns for a QR code in an
+ * image, sample the right points in the image to reconstruct the QR code, accounting for
+ * perspective distortion. It is abstracted since it is relatively expensive and should be allowed
+ * to take advantage of platform-specific optimized implementations, like Sun's Java Advanced
+ * Imaging library, but which may not be available in other environments such as J2ME, and vice
+ * versa.
+ *
+ * The implementation used can be controlled by calling {@link #setGridSampler(GridSampler)}
+ * with an instance of a class which implements this interface.
+ *
+ * @author srowen@google.com (Sean Owen)
+ */
+public abstract class GridSampler {
+
+ private static GridSampler gridSampler;
+
+ /**
+ * Sets the implementation of {@link GridSampler} used by the library. One global
+ * instance is stored, which may sound problematic. But, the implementation provided
+ * ought to be appropriate for the entire platform, and all uses of this library
+ * in the whole lifetime of the JVM. For instance, an Android activity can swap in
+ * an implementation that takes advantage of native platform libraries.
+ *
+ * @param newGridSampler
+ */
+ public static void setGridSampler(GridSampler newGridSampler) {
+ if (newGridSampler == null) {
+ throw new IllegalArgumentException();
+ }
+ gridSampler = newGridSampler;
+ }
+
+ /**
+ * @return the current implementation of {@link GridSampler}
+ */
+ public static GridSampler getInstance() {
+ if (gridSampler == null) {
+ gridSampler = new DefaultGridSampler();
+ }
+ return gridSampler;
+ }
+
+ /**
+ * <p>Samples an image for a square matrix of bits of the given dimension. This is used to extract the
+ * black/white modules of a 2D barcode like a QR Code found in an image. Because this barcode may be
+ * rotated or perspective-distorted, the caller supplies four points in the source image that define
+ * known points in the barcode, so that the image may be sampled appropriately.</p>
+ *
+ * <p>The last eight "from" parameters are four X/Y coordinate pairs of locations of points in
+ * the image that define some significant points in the image to be sample. For example,
+ * these may be the location of finder pattern in a QR Code.</p>
+ *
+ * <p>The first eight "to" parameters are four X/Y coordinate pairs measured in the destination
+ * {@link BitMatrix}, from the top left, where the known points in the image given by the "from" parameters
+ * map to.</p>
+ *
+ * <p>These 16 parameters define the transformation needed to sample the image.</p>
+ *
+ * @param image image to sample
+ * @param dimension width/height of {@link BitMatrix} to sample from iamge
+ * @return {@link BitMatrix} representing a grid of points sampled from the image within a region
+ * defined by the "from" parameters
+ * @throws ReaderException if image can't be sampled, for example, if the transformation defined by
+ * the given points is invalid or results in sampling outside the image boundaries
+ */
+ public abstract BitMatrix sampleGrid(MonochromeBitmapSource image,
+ int dimension,
+ float p1ToX, float p1ToY,
+ float p2ToX, float p2ToY,
+ float p3ToX, float p3ToY,
+ float p4ToX, float p4ToY,
+ float p1FromX, float p1FromY,
+ float p2FromX, float p2FromY,
+ float p3FromX, float p3FromY,
+ float p4FromX, float p4FromY) throws ReaderException;
+
+ /**
+ * <p>Checks a set of points that have been transformed to sample points on an image against
+ * the image's dimensions to see if the endpoints are even within the image.
+ * This method actually only checks the endpoints since the points are assumed to lie
+ * on a line.</p>
+ *
+ * <p>This method will actually "nudge" the endpoints back onto the image if they are found to be barely
+ * (less than 1 pixel) off the image. This accounts for imperfect detection of finder patterns in an image
+ * where the QR Code runs all the way to the image border.</p>
+ *
+ * @param image image into which the points should map
+ * @param points actual points in x1,y1,...,xn,yn form
+ * @throws ReaderException if an endpoint is lies outside the image boundaries
+ */
+ protected static void checkEndpoint(MonochromeBitmapSource image, float[] points) throws ReaderException {
+ int width = image.getWidth();
+ int height = image.getHeight();
+ checkOneEndpoint(points, (int) points[0], (int) points[1], width, height);
+ checkOneEndpoint(points, (int) points[points.length - 2], (int) points[points.length - 1], width, height);
+ }
+
+ private static void checkOneEndpoint(float[] points, int x, int y, int width, int height) throws ReaderException {
+ if (x < -1 || x > width || y < -1 || y > height) {
+ throw new ReaderException("Transformed point out of bounds at " + x + ',' + y);
+ }
+ if (x == -1) {
+ points[0] = 0.0f;
+ }
+ if (y == -1) {
+ points[1] = 0.0f;
+ }
+ if (x == width) {
+ points[0] = width - 1;
+ }
+ if (y == height) {
+ points[1] = height - 1;
+ }
+ }
+
+}
--- /dev/null
+/*\r
+ * Copyright 2007 Google Inc.\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+package com.google.zxing.common;\r
+\r
+/**\r
+ * <p>This class implements a perspective transform in two dimensions. Given four source and four destination\r
+ * points, it will compute the transformation implied between them. The code is based directly upon section\r
+ * 3.4.2 of George Wolberg's "Digital Image Warping"; see pages 54-56.</p>\r
+ *\r
+ * @author srowen@google.com (Sean Owen)\r
+ */\r
+final class PerspectiveTransform {\r
+\r
+ private final float a11, a12, a13, a21, a22, a23, a31, a32, a33;\r
+\r
+ private PerspectiveTransform(float a11, float a21, float a31,\r
+ float a12, float a22, float a32,\r
+ float a13, float a23, float a33) {\r
+ this.a11 = a11;\r
+ this.a12 = a12;\r
+ this.a13 = a13;\r
+ this.a21 = a21;\r
+ this.a22 = a22;\r
+ this.a23 = a23;\r
+ this.a31 = a31;\r
+ this.a32 = a32;\r
+ this.a33 = a33;\r
+ }\r
+\r
+ static PerspectiveTransform quadrilateralToQuadrilateral(float x0, float y0,\r
+ float x1, float y1,\r
+ float x2, float y2,\r
+ float x3, float y3,\r
+ float x0p, float y0p,\r
+ float x1p, float y1p,\r
+ float x2p, float y2p,\r
+ float x3p, float y3p) {\r
+\r
+ PerspectiveTransform qToS = quadrilateralToSquare(x0, y0, x1, y1, x2, y2, x3, y3);\r
+ PerspectiveTransform sToQ = squareToQuadrilateral(x0p, y0p, x1p, y1p, x2p, y2p, x3p, y3p);\r
+ return sToQ.times(qToS);\r
+ }\r
+\r
+ void transformPoints(float[] points) {\r
+ int max = points.length;\r
+ float a11 = this.a11;\r
+ float a12 = this.a12;\r
+ float a13 = this.a13;\r
+ float a21 = this.a21;\r
+ float a22 = this.a22;\r
+ float a23 = this.a23;\r
+ float a31 = this.a31;\r
+ float a32 = this.a32;\r
+ float a33 = this.a33;\r
+ for (int i = 0; i < max; i += 2) {\r
+ float x = points[i];\r
+ float y = points[i + 1];\r
+ float denominator = a13 * x + a23 * y + a33;\r
+ points[i] = (a11 * x + a21 * y + a31) / denominator;\r
+ points[i + 1] = (a12 * x + a22 * y + a32) / denominator;\r
+ }\r
+ }\r
+\r
+ static PerspectiveTransform squareToQuadrilateral(float x0, float y0,\r
+ float x1, float y1,\r
+ float x2, float y2,\r
+ float x3, float y3) {\r
+ float dy2 = y3 - y2;\r
+ float dy3 = y0 - y1 + y2 - y3;\r
+ if (dy2 == 0.0f && dy3 == 0.0f) {\r
+ return new PerspectiveTransform(x1 - x0, x2 - x1, x0,\r
+ y1 - y0, y2 - y1, y0,\r
+ 0.0f, 0.0f, 1.0f);\r
+ } else {\r
+ float dx1 = x1 - x2;\r
+ float dx2 = x3 - x2;\r
+ float dx3 = x0 - x1 + x2 - x3;\r
+ float dy1 = y1 - y2;\r
+ float denominator = dx1 * dy2 - dx2 * dy1;\r
+ float a13 = (dx3 * dy2 - dx2 * dy3) / denominator;\r
+ float a23 = (dx1 * dy3 - dx3 * dy1) / denominator;\r
+ return new PerspectiveTransform(x1 - x0 + a13 * x1, x3 - x0 + a23 * x3, x0,\r
+ y1 - y0 + a13 * y1, y3 - y0 + a23 * y3, y0,\r
+ a13, a23, 1.0f);\r
+ }\r
+ }\r
+\r
+ private static PerspectiveTransform quadrilateralToSquare(float x0, float y0,\r
+ float x1, float y1,\r
+ float x2, float y2,\r
+ float x3, float y3) {\r
+ // Here, the adjoint serves as the inverse:\r
+ return squareToQuadrilateral(x0, y0, x1, y1, x2, y2, x3, y3).buildAdjoint();\r
+ }\r
+\r
+ PerspectiveTransform buildAdjoint() {\r
+ // Adjoint is the transpose of the cofactor matrix:\r
+ return new PerspectiveTransform(a22 * a33 - a23 * a32,\r
+ a23 * a31 - a21 * a33,\r
+ a21 * a32 - a22 * a31,\r
+ a13 * a32 - a12 * a33,\r
+ a11 * a33 - a13 * a31,\r
+ a12 * a31 - a11 * a32,\r
+ a12 * a23 - a13 * a22,\r
+ a13 * a21 - a11 * a23,\r
+ a11 * a22 - a12 * a21);\r
+ }\r
+\r
+ PerspectiveTransform times(PerspectiveTransform other) {\r
+ return new PerspectiveTransform(a11 * other.a11 + a21 * other.a12 + a31 * other.a13,\r
+ a11 * other.a21 + a21 * other.a22 + a31 * other.a23,\r
+ a11 * other.a31 + a21 * other.a32 + a31 * other.a33,\r
+ a12 * other.a11 + a22 * other.a12 + a32 * other.a13,\r
+ a12 * other.a21 + a22 * other.a22 + a32 * other.a23,\r
+ a12 * other.a31 + a22 * other.a32 + a32 * other.a33,\r
+ a13 * other.a11 + a23 * other.a12 + a33 * other.a13,\r
+ a13 * other.a21 + a23 * other.a22 + a33 * other.a23,\r
+ a13 * other.a31 + a23 * other.a32 + a33 * other.a33);\r
+\r
+ }\r
+\r
+}\r
import com.google.zxing.ResultPoint;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.common.DetectorResult;
+import com.google.zxing.common.GridSampler;
import com.google.zxing.qrcode.decoder.Version;
/**
}
- GridSampler sampler = GridSampler.getInstance();
- BitMatrix bits = sampler.sampleGrid(image, topLeft, topRight, bottomLeft, alignmentPattern, dimension);
+ BitMatrix bits = sampleGrid(image, topLeft, topRight, bottomLeft, alignmentPattern, dimension);
ResultPoint[] points;
if (alignmentPattern == null) {
return new DetectorResult(bits, points);
}
+ private static BitMatrix sampleGrid(MonochromeBitmapSource image,
+ ResultPoint topLeft,
+ ResultPoint topRight,
+ ResultPoint bottomLeft,
+ ResultPoint alignmentPattern,
+ int dimension) throws ReaderException {
+ float dimMinusThree = (float) dimension - 3.5f;
+ float bottomRightX;
+ float bottomRightY;
+ float sourceBottomRightX;
+ float sourceBottomRightY;
+ if (alignmentPattern != null) {
+ bottomRightX = alignmentPattern.getX();
+ bottomRightY = alignmentPattern.getY();
+ sourceBottomRightX = sourceBottomRightY = dimMinusThree - 3.0f;
+ } else {
+ // Don't have an alignment pattern, just make up the bottom-right point
+ bottomRightX = (topRight.getX() - topLeft.getX()) + bottomLeft.getX();
+ bottomRightY = (topRight.getY() - topLeft.getY()) + bottomLeft.getY();
+ sourceBottomRightX = sourceBottomRightY = dimMinusThree;
+ }
+
+ GridSampler sampler = GridSampler.getInstance();
+ return sampler.sampleGrid(
+ image,
+ dimension,
+ 3.5f,
+ 3.5f,
+ dimMinusThree,
+ 3.5f,
+ sourceBottomRightX,
+ sourceBottomRightY,
+ 3.5f,
+ dimMinusThree,
+ topLeft.getX(),
+ topLeft.getY(),
+ topRight.getX(),
+ topRight.getY(),
+ bottomRightX,
+ bottomRightY,
+ bottomLeft.getX(),
+ bottomLeft.getY());
+ }
+
/**
* <p>Computes the dimension (number of modules on a size) of the QR Code based on the position
* of the finder patterns and estimated module size.</p>
+++ /dev/null
-/*\r
- * Copyright 2007 Google Inc.\r
- *\r
- * Licensed under the Apache License, Version 2.0 (the "License");\r
- * you may not use this file except in compliance with the License.\r
- * You may obtain a copy of the License at\r
- *\r
- * http://www.apache.org/licenses/LICENSE-2.0\r
- *\r
- * Unless required by applicable law or agreed to in writing, software\r
- * distributed under the License is distributed on an "AS IS" BASIS,\r
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
- * See the License for the specific language governing permissions and\r
- * limitations under the License.\r
- */\r
-\r
-/**\r
- * <p>This class implements a perspective transform in two dimensions. Given four source and four destination\r
- * points, it will compute the transformation implied between them. The code is based directly upon section\r
- * 3.4.2 of George Wolberg's "Digital Image Warping"; see pages 54-56.</p>\r
- *\r
- * @author srowen@google.com (Sean Owen)\r
- */\r
-package com.google.zxing.qrcode.detector;\r
-\r
-final class PerspectiveTransform {\r
-\r
- private final float a11, a12, a13, a21, a22, a23, a31, a32, a33;\r
-\r
- private PerspectiveTransform(float a11, float a21, float a31,\r
- float a12, float a22, float a32,\r
- float a13, float a23, float a33) {\r
- this.a11 = a11;\r
- this.a12 = a12;\r
- this.a13 = a13;\r
- this.a21 = a21;\r
- this.a22 = a22;\r
- this.a23 = a23;\r
- this.a31 = a31;\r
- this.a32 = a32;\r
- this.a33 = a33;\r
- }\r
-\r
- static PerspectiveTransform quadrilateralToQuadrilateral(float x0, float y0,\r
- float x1, float y1,\r
- float x2, float y2,\r
- float x3, float y3,\r
- float x0p, float y0p,\r
- float x1p, float y1p,\r
- float x2p, float y2p,\r
- float x3p, float y3p) {\r
-\r
- PerspectiveTransform qToS = quadrilateralToSquare(x0, y0, x1, y1, x2, y2, x3, y3);\r
- PerspectiveTransform sToQ = squareToQuadrilateral(x0p, y0p, x1p, y1p, x2p, y2p, x3p, y3p);\r
- return sToQ.times(qToS);\r
- }\r
-\r
- void transformPoints(float[] points) {\r
- int max = points.length;\r
- float a11 = this.a11;\r
- float a12 = this.a12;\r
- float a13 = this.a13;\r
- float a21 = this.a21;\r
- float a22 = this.a22;\r
- float a23 = this.a23;\r
- float a31 = this.a31;\r
- float a32 = this.a32;\r
- float a33 = this.a33;\r
- for (int i = 0; i < max; i += 2) {\r
- float x = points[i];\r
- float y = points[i + 1];\r
- float denominator = a13 * x + a23 * y + a33;\r
- points[i] = (a11 * x + a21 * y + a31) / denominator;\r
- points[i + 1] = (a12 * x + a22 * y + a32) / denominator;\r
- }\r
- }\r
-\r
- static PerspectiveTransform squareToQuadrilateral(float x0, float y0,\r
- float x1, float y1,\r
- float x2, float y2,\r
- float x3, float y3) {\r
- float dy2 = y3 - y2;\r
- float dy3 = y0 - y1 + y2 - y3;\r
- if (dy2 == 0.0f && dy3 == 0.0f) {\r
- return new PerspectiveTransform(x1 - x0, x2 - x1, x0,\r
- y1 - y0, y2 - y1, y0,\r
- 0.0f, 0.0f, 1.0f);\r
- } else {\r
- float dx1 = x1 - x2;\r
- float dx2 = x3 - x2;\r
- float dx3 = x0 - x1 + x2 - x3;\r
- float dy1 = y1 - y2;\r
- float denominator = dx1 * dy2 - dx2 * dy1;\r
- float a13 = (dx3 * dy2 - dx2 * dy3) / denominator;\r
- float a23 = (dx1 * dy3 - dx3 * dy1) / denominator;\r
- return new PerspectiveTransform(x1 - x0 + a13 * x1, x3 - x0 + a23 * x3, x0,\r
- y1 - y0 + a13 * y1, y3 - y0 + a23 * y3, y0,\r
- a13, a23, 1.0f);\r
- }\r
- }\r
-\r
- private static PerspectiveTransform quadrilateralToSquare(float x0, float y0,\r
- float x1, float y1,\r
- float x2, float y2,\r
- float x3, float y3) {\r
- // Here, the adjoint serves as the inverse:\r
- return squareToQuadrilateral(x0, y0, x1, y1, x2, y2, x3, y3).buildAdjoint();\r
- }\r
-\r
- PerspectiveTransform buildAdjoint() {\r
- // Adjoint is the transpose of the cofactor matrix:\r
- return new PerspectiveTransform(a22 * a33 - a23 * a32,\r
- a23 * a31 - a21 * a33,\r
- a21 * a32 - a22 * a31,\r
- a13 * a32 - a12 * a33,\r
- a11 * a33 - a13 * a31,\r
- a12 * a31 - a11 * a32,\r
- a12 * a23 - a13 * a22,\r
- a13 * a21 - a11 * a23,\r
- a11 * a22 - a12 * a21);\r
- }\r
-\r
- PerspectiveTransform times(PerspectiveTransform other) {\r
- return new PerspectiveTransform(a11 * other.a11 + a21 * other.a12 + a31 * other.a13,\r
- a11 * other.a21 + a21 * other.a22 + a31 * other.a23,\r
- a11 * other.a31 + a21 * other.a32 + a31 * other.a33,\r
- a12 * other.a11 + a22 * other.a12 + a32 * other.a13,\r
- a12 * other.a21 + a22 * other.a22 + a32 * other.a23,\r
- a12 * other.a31 + a22 * other.a32 + a32 * other.a33,\r
- a13 * other.a11 + a23 * other.a12 + a33 * other.a13,\r
- a13 * other.a21 + a23 * other.a22 + a33 * other.a23,\r
- a13 * other.a31 + a23 * other.a32 + a33 * other.a33);\r
-\r
- }\r
-\r
-}\r
--- /dev/null
+/*
+ * Copyright 2007 Google Inc.
+ *
+ * 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.common;
+
+import junit.framework.TestCase;
+
+/**
+ * @author srowen@google.com (Sean Owen)
+ */
+public final class PerspectiveTransformTestCase extends TestCase {
+
+ private static final float EPSILON = 0.0001f;
+
+ public void testSquareToQuadrilateral() {
+ PerspectiveTransform pt = PerspectiveTransform.squareToQuadrilateral(
+ 2.0f, 3.0f, 10.0f, 4.0f, 16.0f, 15.0f, 4.0f, 9.0f);
+ assertPointEquals(2.0f, 3.0f, 0.0f, 0.0f, pt);
+ assertPointEquals(10.0f, 4.0f, 1.0f, 0.0f, pt);
+ assertPointEquals(4.0f, 9.0f, 0.0f, 1.0f, pt);
+ assertPointEquals(16.0f, 15.0f, 1.0f, 1.0f, pt);
+ assertPointEquals(6.535211f, 6.8873234f, 0.5f, 0.5f, pt);
+ assertPointEquals(48.0f, 42.42857f, 1.5f, 1.5f, pt);
+ }
+
+ public void testQuadrilateralToQuadrilateral() {
+ PerspectiveTransform pt = PerspectiveTransform.quadrilateralToQuadrilateral(
+ 2.0f, 3.0f, 10.0f, 4.0f, 16.0f, 15.0f, 4.0f, 9.0f,
+ 103.0f, 110.0f, 300.0f, 120.0f, 290.0f, 270.0f, 150.0f, 280.0f);
+ assertPointEquals(103.0f, 110.0f, 2.0f, 3.0f, pt);
+ assertPointEquals(300.0f, 120.0f, 10.0f, 4.0f, pt);
+ assertPointEquals(290.0f, 270.0f, 16.0f, 15.0f, pt);
+ assertPointEquals(150.0f, 280.0f, 4.0f, 9.0f, pt);
+ assertPointEquals(7.1516876f, -64.60185f, 0.5f, 0.5f, pt);
+ assertPointEquals(328.09116f, 334.16385f, 50.0f, 50.0f, pt);
+ }
+
+ private static void assertPointEquals(float expectedX, float expectedY, float sourceX, float sourceY, PerspectiveTransform pt) {
+ float[] points = new float[]{sourceX, sourceY};
+ pt.transformPoints(points);
+ assertEquals(expectedX, points[0], EPSILON);
+ assertEquals(expectedY, points[1], EPSILON);
+ }
+
+}
\ No newline at end of file