2 * Copyright 2008 ZXing authors
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
16 package com.google.zxing.common;
18 import com.google.zxing.MonochromeBitmapSource;
19 import com.google.zxing.BlackPointEstimationMethod;
20 import com.google.zxing.ReaderException;
23 * @author dswitkin@google.com (Daniel Switkin)
25 public abstract class BaseMonochromeBitmapSource implements MonochromeBitmapSource {
27 private static final int LUMINANCE_BITS = 5;
28 private static final int LUMINANCE_SHIFT = 8 - LUMINANCE_BITS;
29 private static final int LUMINANCE_BUCKETS = 1 << LUMINANCE_BITS;
31 private int blackPoint;
32 private BlackPointEstimationMethod lastMethod;
33 private int lastArgument;
35 protected BaseMonochromeBitmapSource() {
41 public boolean isBlack(int x, int y) {
42 return getLuminance(x, y) < blackPoint;
45 public BitArray getBlackRow(int y, BitArray row, int startX, int getWidth) {
46 if (row == null || row.getSize() < getWidth) {
47 row = new BitArray(getWidth);
52 // If the current decoder calculated the blackPoint based on one row, assume we're trying to
53 // decode a 1D barcode, and apply some sharpening.
54 // TODO: We may want to add a fifth parameter to request the amount of shapening to be done.
55 cacheRowForLuminance(y);
56 if (lastMethod.equals(BlackPointEstimationMethod.ROW_SAMPLING)) {
57 int left = getLuminance(startX, y);
58 int center = getLuminance(startX + 1, y);
59 for (int x = 1; x < getWidth - 1; x++) {
60 int right = getLuminance(startX + x + 1, y);
61 // Simple -1 4 -1 box filter with a weight of 2
62 int luminance = ((center << 2) - left - right) >> 1;
63 if (luminance < blackPoint) {
70 for (int x = 0; x < getWidth; x++) {
71 if (getLuminance(startX + x, y) < blackPoint) {
79 public BitArray getBlackColumn(int x, BitArray column, int startY, int getHeight) {
80 if (column == null || column.getSize() < getHeight) {
81 column = new BitArray(getHeight);
86 cacheColumnForLuminance(x);
87 // We don't handle "row sampling" specially here
88 for (int y = 0; y < getHeight; y++) {
89 if (getLuminance(x, startY + y) < blackPoint) {
96 public void estimateBlackPoint(BlackPointEstimationMethod method, int argument) throws ReaderException {
97 if (!method.equals(lastMethod) || argument != lastArgument) {
98 int width = getWidth();
99 int height = getHeight();
100 int[] histogram = new int[LUMINANCE_BUCKETS];
101 if (method.equals(BlackPointEstimationMethod.TWO_D_SAMPLING)) {
102 int minDimension = width < height ? width : height;
103 int startX = (width - minDimension) >> 1;
104 int startY = (height - minDimension) >> 1;
105 for (int n = 0; n < minDimension; n++) {
106 int luminance = getLuminance(startX + n, startY + n);
107 histogram[luminance >> LUMINANCE_SHIFT]++;
109 } else if (method.equals(BlackPointEstimationMethod.ROW_SAMPLING)) {
110 if (argument < 0 || argument >= height) {
111 throw new IllegalArgumentException("Row is not within the image: " + argument);
113 cacheRowForLuminance(argument);
114 for (int x = 0; x < width; x++) {
115 int luminance = getLuminance(x, argument);
116 histogram[luminance >> LUMINANCE_SHIFT]++;
119 throw new IllegalArgumentException("Unknown method: " + method);
121 blackPoint = BlackPointEstimator.estimate(histogram) << LUMINANCE_SHIFT;
123 lastArgument = argument;
127 public BlackPointEstimationMethod getLastEstimationMethod() {
131 public MonochromeBitmapSource rotateCounterClockwise() {
132 throw new IllegalArgumentException("Rotate not supported");
135 public boolean isRotateSupported() {
139 // These two methods should not need to exist because they are defined in the interface that
140 // this abstract class implements. However this seems to cause problems on some Nokias.
141 // So we write these redundant declarations.
143 public abstract int getHeight();
145 public abstract int getWidth();
147 public abstract int getLuminance(int x, int y);
149 public abstract void cacheRowForLuminance(int y);
151 public abstract void cacheColumnForLuminance(int x);