Bug fix from K. Kakima
[zxing.git] / core / src / com / google / zxing / qrcode / detector / GridSampler.java
1 /*
2  * Copyright 2007 Google Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 package com.google.zxing.qrcode.detector;
18
19 import com.google.zxing.MonochromeBitmapSource;
20 import com.google.zxing.ReaderException;
21 import com.google.zxing.common.BitMatrix;
22
23 /**
24  * Implementations of this class can, given locations of finder patterns for a QR code in an
25  * image, sample the right points in the image to reconstruct the QR code, accounting for
26  * perspective distortion. It is abstracted since it is relatively expensive and should be allowed
27  * to take advantage of platform-specific optimized implementations, like Sun's Java Advanced
28  * Imaging library, but which may not be available in other environments such as J2ME, and vice
29  * versa.
30  *
31  * The implementation used can be controlled by calling {@link #setGridSamplerClassName(String)}
32  * with the name of a class which implements this interface.
33  *
34  * @author srowen@google.com (Sean Owen)
35  */
36 public abstract class GridSampler {
37
38   private static final String DEFAULT_IMPL_CLASS = "com.google.zxing.qrcode.detector.DefaultGridSampler";
39
40   private static String gridSamplerClassName = DEFAULT_IMPL_CLASS;
41   private static GridSampler gridSampler;
42
43   /**
44    * <p>Sets the (fully-qualified) name of the implementation of {@link GridSampler} which will be
45    * returned from {@link #getInstance()}.</p>
46    *
47    * @param className {@link GridSampler} implementation to instantiate
48    */
49   public static void setGridSamplerClassName(String className) {
50     if (className == null) {
51       throw new IllegalArgumentException();
52     }
53     gridSamplerClassName = className;
54   }
55
56   /**
57    * @return the current implementation of {@link GridSampler}, instantiating one if one does
58    *  not already exist. The class which is instantied may be set by
59    *  {@link #setGridSamplerClassName(String)}
60    */
61   public static GridSampler getInstance() {
62     if (gridSampler == null) {
63       // We don't need to synchronize this -- don't really care if two threads initialize at once.
64       // The second one will win.
65       try {
66         Class gridSamplerClass = Class.forName(gridSamplerClassName);
67         gridSampler = (GridSampler) gridSamplerClass.newInstance();
68       } catch (ClassNotFoundException cnfe) {
69         // The exceptions below would represent bad programming errors;
70         // For J2ME we're punting them out with RuntimeException
71         throw new RuntimeException(cnfe.toString());
72       } catch (IllegalAccessException iae) {
73         throw new RuntimeException(iae.toString());
74       } catch (InstantiationException ie) {
75         throw new RuntimeException(ie.toString());
76       }
77     }
78     return gridSampler;
79   }
80
81   /**
82    * <p>Given an image, locations of a QR Code's finder patterns and bottom-right alignment pattern,
83    * and the presumed dimension in modules of the QR Code, implemntations of this method extract
84    * the QR Code from the image by sampling the points in the image which should correspond to the
85    * modules of the QR Code.</p>
86    *
87    * @param image image to sample
88    * @param topLeft top-left finder pattern location
89    * @param topRight top-right finder pattern location
90    * @param bottomLeft bottom-left finder pattern location
91    * @param alignmentPattern bottom-right alignment pattern location
92    * @param dimension dimension of QR Code
93    * @return {@link BitMatrix} representing QR Code's modules
94    * @throws ReaderException if QR Code cannot be reasonably sampled -- for example if the location
95    *  of the finder patterns imply a transformation that would require sampling off the image
96    */
97   protected abstract BitMatrix sampleGrid(MonochromeBitmapSource image,
98                                           FinderPattern topLeft,
99                                           FinderPattern topRight,
100                                           FinderPattern bottomLeft,
101                                           AlignmentPattern alignmentPattern,
102                                           int dimension) throws ReaderException;
103
104   /**
105    * <p>Checks a set of points that have been transformed to sample points on an image against
106    * the image's dimensions to see if the endpoints are even within the image.
107    * This method actually only checks the endpoints since the points are assumed to lie
108    * on a line.</p>
109    *
110    * @param image image into which the points should map
111    * @param points actual points in x1,y1,...,xn,yn form
112    * @throws ReaderException if an endpoint is lies outside the image boundaries
113    */
114   protected static void checkEndpoint(MonochromeBitmapSource image, float[] points) throws ReaderException {
115     int x = (int) points[0];
116     int y = (int) points[1];
117     if (x < 0 || x >= image.getWidth() || y < 0 || y >= image.getHeight()) {
118       throw new ReaderException("Transformed point out of bounds at " + x + ',' + y);
119     }
120     x = (int) points[points.length - 2];
121     y = (int) points[points.length - 1];
122     if (x < 0 || x >= image.getWidth() || y < 0 || y >= image.getHeight()) {
123       throw new ReaderException("Transformed point out of bounds at " + x + ',' + y);
124     }
125   }
126
127 }