2 * Licensed under the Apache License, Version 2.0 (the "License");
\r
3 * you may not use this file except in compliance with the License.
\r
4 * You may obtain a copy of the License at
\r
6 * http://www.apache.org/licenses/LICENSE-2.0
\r
8 * Unless required by applicable law or agreed to in writing, software
\r
9 * distributed under the License is distributed on an "AS IS" BASIS,
\r
10 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
\r
11 * See the License for the specific language governing permissions and
\r
12 * limitations under the License.
\r
16 using BitArray = com.google.zxing.common.BitArray;
\r
17 using com.google.zxing.common;
\r
18 namespace com.google.zxing
\r
21 * @author dswitkin@google.com (Daniel Switkin)
\r
23 public abstract class BaseMonochromeBitmapSource: MonochromeBitmapSource
\r
25 private static int LUMINANCE_BITS = 5;
\r
26 private static int LUMINANCE_SHIFT = 8 - LUMINANCE_BITS;
\r
27 private static int LUMINANCE_BUCKETS = 1 << LUMINANCE_BITS;
\r
29 private int blackPoint;
\r
30 private BlackPointEstimationMethod lastMethod;
\r
31 private int lastArgument;
\r
32 private int[] luminances;
\r
34 protected BaseMonochromeBitmapSource() {
\r
40 private void initLuminances() {
\r
41 if (luminances == null) {
\r
42 int width = getWidth();
\r
43 int height = getHeight();
\r
44 int max = width > height ? width : height;
\r
45 luminances = new int[max];
\r
49 public bool isBlack(int x, int y) {
\r
50 return getLuminance(x, y) < blackPoint;
\r
53 public BitArray getBlackRow(int y, BitArray row, int startX, int getWidth) {
\r
54 if (row == null || row.getSize() < getWidth) {
\r
55 row = new BitArray(getWidth);
\r
60 // Reuse the same int array each time
\r
62 luminances = getLuminanceRow(y, luminances);
\r
64 // If the current decoder calculated the blackPoint based on one row, assume we're trying to
\r
65 // decode a 1D barcode, and apply some sharpening.
\r
66 if (lastMethod.Equals(BlackPointEstimationMethod.ROW_SAMPLING)) {
\r
67 int left = luminances[startX];
\r
68 int center = luminances[startX + 1];
\r
69 for (int x = 1; x < getWidth - 1; x++) {
\r
70 int right = luminances[startX + x + 1];
\r
71 // Simple -1 4 -1 box filter with a weight of 2
\r
72 int luminance = ((center << 2) - left - right) >> 1;
\r
73 if (luminance < blackPoint) {
\r
80 for (int x = 0; x < getWidth; x++) {
\r
81 if (luminances[startX + x] < blackPoint) {
\r
89 public BitArray getBlackColumn(int x, BitArray column, int startY, int getHeight) {
\r
90 if (column == null || column.getSize() < getHeight) {
\r
91 column = new BitArray(getHeight);
\r
96 // Reuse the same int array each time
\r
98 luminances = getLuminanceColumn(x, luminances);
\r
100 // We don't handle "row sampling" specially here
\r
101 for (int y = 0; y < getHeight; y++) {
\r
102 if (luminances[startY + y] < blackPoint) {
\r
109 public void estimateBlackPoint(BlackPointEstimationMethod method, int argument){
\r
110 if (!method.Equals(lastMethod) || argument != lastArgument) {
\r
111 int width = getWidth();
\r
112 int height = getHeight();
\r
113 int[] histogram = new int[LUMINANCE_BUCKETS];
\r
114 if (method.Equals(BlackPointEstimationMethod.TWO_D_SAMPLING)) {
\r
115 int minDimension = width < height ? width : height;
\r
116 int startX = (width - minDimension) >> 1;
\r
117 int startY = (height - minDimension) >> 1;
\r
118 for (int n = 0; n < minDimension; n++) {
\r
119 int luminance = getLuminance(startX + n, startY + n);
\r
120 histogram[luminance >> LUMINANCE_SHIFT]++;
\r
122 } else if (method.Equals(BlackPointEstimationMethod.ROW_SAMPLING)) {
\r
123 if (argument < 0 || argument >= height) {
\r
124 throw new Exception("Row is not within the image: " + argument);
\r
127 luminances = getLuminanceRow(argument, luminances);
\r
128 for (int x = 0; x < width; x++) {
\r
129 histogram[luminances[x] >> LUMINANCE_SHIFT]++;
\r
132 throw new Exception("Unknown method: " + method);
\r
134 blackPoint = BlackPointEstimator.estimate(histogram) << LUMINANCE_SHIFT;
\r
135 lastMethod = method;
\r
136 lastArgument = argument;
\r
140 public BlackPointEstimationMethod getLastEstimationMethod() {
\r
144 public MonochromeBitmapSource rotateCounterClockwise() {
\r
145 throw new Exception("Rotate not supported");
\r
148 public bool isRotateSupported() {
\r
152 // These two methods should not need to exist because they are defined in the interface that
\r
153 // this abstract class implements. However this seems to cause problems on some Nokias.
\r
154 // So we write these redundant declarations.
\r
156 public abstract int getHeight();
\r
158 public abstract int getWidth();
\r
161 * Retrieves the luminance at the pixel x,y in the bitmap. This method is only used for estimating
\r
162 * the black point and implementing getBlackRow() - it is not meant for decoding, hence it is not
\r
163 * part of MonochromeBitmapSource itself, and is protected.
\r
165 * @param x The x coordinate in the image.
\r
166 * @param y The y coordinate in the image.
\r
167 * @return The luminance value between 0 and 255.
\r
169 protected abstract int getLuminance(int x, int y);
\r
172 * This is the main mechanism for retrieving luminance data. It is dramatically more efficient
\r
173 * than repeatedly calling getLuminance(). As above, this is not meant for decoders.
\r
175 * @param y The row to fetch
\r
176 * @param row The array to write luminance values into. It is <b>strongly</b> suggested that you
\r
177 * allocate this yourself, making sure row.length >= getWidth(), and reuse the same
\r
178 * array on subsequent calls for performance. If you pass null, you will be flogged,
\r
179 * but then I will take pity on you and allocate a sufficient array internally.
\r
180 * @return The array containing the luminance data. This is the same as row if it was usable.
\r
182 protected abstract int[] getLuminanceRow(int y, int[] row);
\r
185 * The same as getLuminanceRow(), but for columns.
\r
187 * @param x The column to fetch
\r
188 * @param column The array to write luminance values into. See above.
\r
189 * @return The array containing the luminance data.
\r
191 protected abstract int[] getLuminanceColumn(int x, int[] column);
\r