X-Git-Url: http://git.rot13.org/?a=blobdiff_plain;f=core%2Fsrc%2Fcom%2Fgoogle%2Fzxing%2Fcommon%2FBaseMonochromeBitmapSource.java;h=0e6699e8ffb13e409cbad9fa80dad7f49f605734;hb=7eec24ee881d16e10dac4228adb5aa199eec0b29;hp=5c7667d6605925401c17f2602ec4847cc4311db0;hpb=6dea64cb666459bd0339ed27174faffd685ce61a;p=zxing.git diff --git a/core/src/com/google/zxing/common/BaseMonochromeBitmapSource.java b/core/src/com/google/zxing/common/BaseMonochromeBitmapSource.java index 5c7667d6..0e6699e8 100644 --- a/core/src/com/google/zxing/common/BaseMonochromeBitmapSource.java +++ b/core/src/com/google/zxing/common/BaseMonochromeBitmapSource.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008 Google Inc. + * Copyright 2008 ZXing authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,20 +24,34 @@ import com.google.zxing.ReaderException; */ public abstract class BaseMonochromeBitmapSource implements MonochromeBitmapSource { - private int blackPoint; - private BlackPointEstimationMethod lastMethod; - private int lastArgument; - private static final int LUMINANCE_BITS = 5; private static final int LUMINANCE_SHIFT = 8 - LUMINANCE_BITS; private static final int LUMINANCE_BUCKETS = 1 << LUMINANCE_BITS; - public BaseMonochromeBitmapSource() { + private final int height; + private final int width; + private int blackPoint; + private BlackPointEstimationMethod lastMethod; + private int lastArgument; + private int[] luminances; + + protected BaseMonochromeBitmapSource(int width, int height) { + this.height = height; + this.width = width; blackPoint = 0x7F; lastMethod = null; lastArgument = 0; } + private void initLuminances() { + if (luminances == null) { + int width = getWidth(); + int height = getHeight(); + int max = width > height ? width : height; + luminances = new int[max]; + } + } + public boolean isBlack(int x, int y) { return getLuminance(x, y) < blackPoint; } @@ -49,15 +63,17 @@ public abstract class BaseMonochromeBitmapSource implements MonochromeBitmapSour row.clear(); } + // Reuse the same int array each time + initLuminances(); + luminances = getLuminanceRow(y, luminances); + // If the current decoder calculated the blackPoint based on one row, assume we're trying to // decode a 1D barcode, and apply some sharpening. - // TODO: We may want to add a fifth parameter to request the amount of shapening to be done. - cacheRowForLuminance(y); - if (lastMethod == BlackPointEstimationMethod.ROW_SAMPLING) { - int left = getLuminance(startX, y); - int center = getLuminance(startX + 1, y); + if (lastMethod.equals(BlackPointEstimationMethod.ROW_SAMPLING)) { + int left = luminances[startX]; + int center = luminances[startX + 1]; for (int x = 1; x < getWidth - 1; x++) { - int right = getLuminance(startX + x + 1, y); + int right = luminances[startX + x + 1]; // Simple -1 4 -1 box filter with a weight of 2 int luminance = ((center << 2) - left - right) >> 1; if (luminance < blackPoint) { @@ -68,7 +84,7 @@ public abstract class BaseMonochromeBitmapSource implements MonochromeBitmapSour } } else { for (int x = 0; x < getWidth; x++) { - if (getLuminance(startX + x, y) < blackPoint) { + if (luminances[startX + x] < blackPoint) { row.set(x); } } @@ -76,10 +92,25 @@ public abstract class BaseMonochromeBitmapSource implements MonochromeBitmapSour return row; } - public abstract int getHeight(); - public abstract int getWidth(); - public abstract int getLuminance(int x, int y); - public abstract void cacheRowForLuminance(int y); + public BitArray getBlackColumn(int x, BitArray column, int startY, int getHeight) { + if (column == null || column.getSize() < getHeight) { + column = new BitArray(getHeight); + } else { + column.clear(); + } + + // Reuse the same int array each time + initLuminances(); + luminances = getLuminanceColumn(x, luminances); + + // We don't handle "row sampling" specially here + for (int y = 0; y < getHeight; y++) { + if (luminances[startY + y] < blackPoint) { + column.set(y); + } + } + return column; + } public void estimateBlackPoint(BlackPointEstimationMethod method, int argument) throws ReaderException { if (!method.equals(lastMethod) || argument != lastArgument) { @@ -98,9 +129,10 @@ public abstract class BaseMonochromeBitmapSource implements MonochromeBitmapSour if (argument < 0 || argument >= height) { throw new IllegalArgumentException("Row is not within the image: " + argument); } + initLuminances(); + luminances = getLuminanceRow(argument, luminances); for (int x = 0; x < width; x++) { - int luminance = getLuminance(x, argument); - histogram[luminance >> LUMINANCE_SHIFT]++; + histogram[luminances[x] >> LUMINANCE_SHIFT]++; } } else { throw new IllegalArgumentException("Unknown method: " + method); @@ -116,12 +148,56 @@ public abstract class BaseMonochromeBitmapSource implements MonochromeBitmapSour } public MonochromeBitmapSource rotateCounterClockwise() { - throw new IllegalStateException("Rotate not supported"); + throw new IllegalArgumentException("Rotate not supported"); } public boolean isRotateSupported() { return false; } + public final int getHeight() { + return height; + } + + public final int getWidth() { + return width; + } + + // These methods below should not need to exist because they are defined in the interface that + // this abstract class implements. However this seems to cause problems on some Nokias. + // So we write these redundant declarations. + + /** + * Retrieves the luminance at the pixel x,y in the bitmap. This method is only used for estimating + * the black point and implementing getBlackRow() - it is not meant for decoding, hence it is not + * part of MonochromeBitmapSource itself, and is protected. + * + * @param x The x coordinate in the image. + * @param y The y coordinate in the image. + * @return The luminance value between 0 and 255. + */ + protected abstract int getLuminance(int x, int y); + + /** + * This is the main mechanism for retrieving luminance data. It is dramatically more efficient + * than repeatedly calling getLuminance(). As above, this is not meant for decoders. + * + * @param y The row to fetch + * @param row The array to write luminance values into. It is strongly suggested that you + * allocate this yourself, making sure row.length >= getWidth(), and reuse the same + * array on subsequent calls for performance. If you pass null, you will be flogged, + * but then I will take pity on you and allocate a sufficient array internally. + * @return The array containing the luminance data. This is the same as row if it was usable. + */ + protected abstract int[] getLuminanceRow(int y, int[] row); + + /** + * The same as getLuminanceRow(), but for columns. + * + * @param x The column to fetch + * @param column The array to write luminance values into. See above. + * @return The array containing the luminance data. + */ + protected abstract int[] getLuminanceColumn(int x, int[] column); }