Changed the order of the BaseMonochromeBitmapSource constructor arguments to be width...
[zxing.git] / core / src / com / google / zxing / common / BaseMonochromeBitmapSource.java
index dd6e5f1..0e6699e 100644 (file)
@@ -28,16 +28,30 @@ public abstract class BaseMonochromeBitmapSource implements MonochromeBitmapSour
   private static final int LUMINANCE_SHIFT = 8 - LUMINANCE_BITS;
   private static final int LUMINANCE_BUCKETS = 1 << LUMINANCE_BITS;
 
+  private final int height;
+  private final int width;
   private int blackPoint;
   private BlackPointEstimationMethod lastMethod;
   private int lastArgument;
+  private int[] luminances;
 
-  protected BaseMonochromeBitmapSource() {
+  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.equals(BlackPointEstimationMethod.ROW_SAMPLING)) {
-      int left = getLuminance(startX, y);
-      int center = getLuminance(startX + 1, y);
+      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);
         }
       }
@@ -83,10 +99,13 @@ public abstract class BaseMonochromeBitmapSource implements MonochromeBitmapSour
       column.clear();
     }
 
-    cacheColumnForLuminance(x);
+    // 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 (getLuminance(x, startY + y) < blackPoint) {
+      if (luminances[startY + y] < blackPoint) {
         column.set(y);
       }
     }
@@ -110,10 +129,10 @@ public abstract class BaseMonochromeBitmapSource implements MonochromeBitmapSour
         if (argument < 0 || argument >= height) {
           throw new IllegalArgumentException("Row is not within the image: " + argument);
         }
-        cacheRowForLuminance(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);
@@ -136,18 +155,49 @@ public abstract class BaseMonochromeBitmapSource implements MonochromeBitmapSour
     return false;
   }
 
-  // These two methods 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.
-
-  public abstract int getHeight();
-
-  public abstract int getWidth();
+  public final int getHeight() {
+    return height;
+  }
 
-  public abstract int getLuminance(int x, int y);
+  public final int getWidth() {
+    return width;
+  }
 
-  public abstract void cacheRowForLuminance(int y);
+  // 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.
 
-  public abstract void cacheColumnForLuminance(int x);
+  /**
+   * 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 <b>strongly</b> 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);
 
 }