diff --git a/android/build.xml b/android/build.xml index 04bd85eb3..f19d5f4b8 100644 --- a/android/build.xml +++ b/android/build.xml @@ -128,8 +128,6 @@ - - diff --git a/android/src/com/google/zxing/client/android/AndroidGraphicsGridSampler.java b/android/src/com/google/zxing/client/android/AndroidGraphicsGridSampler.java new file mode 100755 index 000000000..d91deda1d --- /dev/null +++ b/android/src/com/google/zxing/client/android/AndroidGraphicsGridSampler.java @@ -0,0 +1,112 @@ +/* + * 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.client.android; + +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; + +/** + * Implementation based on Android's + * {@link Matrix#setPolyToPoly(float[], int, float[], int, int)} + * class, which should offer faster performance for these matrix + * operations. + * + * @author srowen@google.com (Sean Owen) + */ +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; + } + + Matrix transformMatrix = new Matrix(); + boolean succeeded = transformMatrix.setPolyToPoly( + new float[] { + topLeft.getX(), + topLeft.getY(), + topRight.getX(), + topRight.getY(), + bottomLeft.getX(), + bottomLeft.getY(), + bottomRightX, + bottomRightY + }, + 0, + new float[] { + 3.5f, + 3.5f, + dimMinusThree, + 3.5f, + 3.5f, + dimMinusThree, + sourceBottomRightX, + sourceBottomRightY, + }, + 0, + 4 + ); + if (!succeeded) { + throw new ReaderException("Could not establish transformation matrix"); + } + + 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; + } + transformMatrix.mapPoints(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; + } + +} diff --git a/android/src/com/google/zxing/client/android/BarcodeReaderCaptureActivity.java b/android/src/com/google/zxing/client/android/BarcodeReaderCaptureActivity.java index 38a48ee59..3b72d2689 100644 --- a/android/src/com/google/zxing/client/android/BarcodeReaderCaptureActivity.java +++ b/android/src/com/google/zxing/client/android/BarcodeReaderCaptureActivity.java @@ -63,6 +63,9 @@ public final class BarcodeReaderCaptureActivity extends Activity { workerThread = new WorkerThread(surfaceView, cameraManager, messageHandler); workerThread.requestPreviewLoop(); workerThread.start(); + + // TODO re-enable this when issues with Matrix.setPolyToPoly() are resolved + //GridSampler.setGridSampler(new AndroidGraphicsGridSampler()); } @Override diff --git a/core/src/com/google/zxing/qrcode/detector/GridSampler.java b/core/src/com/google/zxing/qrcode/detector/GridSampler.java index c9df5b868..880ad485d 100644 --- a/core/src/com/google/zxing/qrcode/detector/GridSampler.java +++ b/core/src/com/google/zxing/qrcode/detector/GridSampler.java @@ -28,52 +28,37 @@ import com.google.zxing.common.BitMatrix; * 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 #setGridSamplerClassName(String)} - * with the name of a class which implements this interface. + * 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 final String DEFAULT_IMPL_CLASS = "com.google.zxing.qrcode.detector.DefaultGridSampler"; - - private static String gridSamplerClassName = DEFAULT_IMPL_CLASS; private static GridSampler gridSampler; /** - *

Sets the (fully-qualified) name of the implementation of {@link GridSampler} which will be - * returned from {@link #getInstance()}.

- * - * @param className {@link GridSampler} implementation to instantiate + * 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 setGridSamplerClassName(String className) { - if (className == null) { + public static void setGridSampler(GridSampler newGridSampler) { + if (newGridSampler == null) { throw new IllegalArgumentException(); } - gridSamplerClassName = className; + gridSampler = newGridSampler; } /** - * @return the current implementation of {@link GridSampler}, instantiating one if one does - * not already exist. The class which is instantied may be set by - * {@link #setGridSamplerClassName(String)} + * @return the current implementation of {@link GridSampler} */ public static GridSampler getInstance() { if (gridSampler == null) { - // We don't need to synchronize this -- don't really care if two threads initialize at once. - // The second one will win. - try { - Class gridSamplerClass = Class.forName(gridSamplerClassName); - gridSampler = (GridSampler) gridSamplerClass.newInstance(); - } catch (ClassNotFoundException cnfe) { - // The exceptions below would represent bad programming errors; - // For J2ME we're punting them out with RuntimeException - throw new RuntimeException(cnfe.toString()); - } catch (IllegalAccessException iae) { - throw new RuntimeException(iae.toString()); - } catch (InstantiationException ie) { - throw new RuntimeException(ie.toString()); - } + gridSampler = new DefaultGridSampler(); } return gridSampler; }