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 void estimateBlackPoint(BlackPointEstimationMethod method, int argument) throws ReaderException {
80 if (!method.equals(lastMethod) || argument != lastArgument) {
81 int width = getWidth();
82 int height = getHeight();
83 int[] histogram = new int[LUMINANCE_BUCKETS];
84 if (method.equals(BlackPointEstimationMethod.TWO_D_SAMPLING)) {
85 int minDimension = width < height ? width : height;
86 int startX = (width - minDimension) >> 1;
87 int startY = (height - minDimension) >> 1;
88 for (int n = 0; n < minDimension; n++) {
89 int luminance = getLuminance(startX + n, startY + n);
90 histogram[luminance >> LUMINANCE_SHIFT]++;
92 } else if (method.equals(BlackPointEstimationMethod.ROW_SAMPLING)) {
93 if (argument < 0 || argument >= height) {
94 throw new IllegalArgumentException("Row is not within the image: " + argument);
96 cacheRowForLuminance(argument);
97 for (int x = 0; x < width; x++) {
98 int luminance = getLuminance(x, argument);
99 histogram[luminance >> LUMINANCE_SHIFT]++;
102 throw new IllegalArgumentException("Unknown method: " + method);
104 blackPoint = BlackPointEstimator.estimate(histogram) << LUMINANCE_SHIFT;
106 lastArgument = argument;
110 public BlackPointEstimationMethod getLastEstimationMethod() {
114 public MonochromeBitmapSource rotateCounterClockwise() {
115 throw new IllegalArgumentException("Rotate not supported");
118 public boolean isRotateSupported() {
122 // These two methods should not need to exist because they are defined in the interface that
123 // this abstract class implements. However this seems to cause problems on some Nokias.
124 // So we write these redundant declarations.
126 public abstract int getHeight();
128 public abstract int getWidth();