Add basic Code 128, Code 39, ITF writers, per Erik
[zxing.git] / core / src / com / google / zxing / oned / ITFReader.java
index 49f065d..b380972 100644 (file)
 package com.google.zxing.oned;\r
 \r
 import com.google.zxing.BarcodeFormat;\r
-import com.google.zxing.ReaderException;\r
+import com.google.zxing.DecodeHintType;\r
+import com.google.zxing.FormatException;\r
+import com.google.zxing.NotFoundException;\r
 import com.google.zxing.Result;\r
 import com.google.zxing.ResultPoint;\r
-import com.google.zxing.DecodeHintType;\r
 import com.google.zxing.common.BitArray;\r
-import com.google.zxing.common.GenericResultPoint;\r
 \r
 import java.util.Hashtable;\r
 \r
 /**\r
  * <p>Implements decoding of the ITF format.</p>\r
  *\r
- * <p>"ITF" stands for Interleaved Two of Five. This Reader will scan ITF barcode with 6, 10 or 14 digits.\r
- * The checksum is optional and is not applied by this Reader. The consumer of the decoded value\r
- * will have to apply a checksum if required.</p>\r
+ * <p>"ITF" stands for Interleaved Two of Five. This Reader will scan ITF barcode with 6, 10 or 14\r
+ * digits. The checksum is optional and is not applied by this Reader. The consumer of the decoded\r
+ * value will have to apply a checksum if required.</p>\r
  *\r
  * <p><a href="http://en.wikipedia.org/wiki/Interleaved_2_of_5">http://en.wikipedia.org/wiki/Interleaved_2_of_5</a>\r
  * is a great reference for Interleaved 2 of 5 information.</p>\r
  *\r
  * @author kevin.osullivan@sita.aero, SITA Lab.\r
  */\r
-public final class ITFReader extends AbstractOneDReader {\r
+public final class ITFReader extends OneDReader {\r
 \r
   private static final int MAX_AVG_VARIANCE = (int) (PATTERN_MATCH_RESULT_SCALE_FACTOR * 0.42f);\r
   private static final int MAX_INDIVIDUAL_VARIANCE = (int) (PATTERN_MATCH_RESULT_SCALE_FACTOR * 0.8f);\r
@@ -46,7 +46,7 @@ public final class ITFReader extends AbstractOneDReader {
   private static final int W = 3; // Pixel width of a wide line\r
   private static final int N = 1; // Pixed width of a narrow line\r
 \r
-  private static final int[] DEFAULT_ALLOWED_LENGTHS = { 6, 10, 14 };\r
+  private static final int[] DEFAULT_ALLOWED_LENGTHS = { 6, 10, 14, 44 };\r
 \r
   // Stores the actual narrow line width of the image being decoded.\r
   private int narrowLineWidth = -1;\r
@@ -63,7 +63,7 @@ public final class ITFReader extends AbstractOneDReader {
   /**\r
    * Patterns of Wide / Narrow lines to indicate each digit\r
    */\r
-  private static final int[][] PATTERNS = {\r
+  static final int[][] PATTERNS = {\r
       {N, N, W, W, N}, // 0\r
       {W, N, N, N, W}, // 1\r
       {N, W, N, N, W}, // 2\r
@@ -76,19 +76,21 @@ public final class ITFReader extends AbstractOneDReader {
       {N, W, N, W, N}  // 9\r
   };\r
 \r
-  public Result decodeRow(int rowNumber, BitArray row, Hashtable hints) throws ReaderException {\r
-\r
-    StringBuffer result = new StringBuffer(20);\r
+  public Result decodeRow(int rowNumber, BitArray row, Hashtable hints) throws FormatException, NotFoundException {\r
 \r
     // Find out where the Middle section (payload) starts & ends\r
     int[] startRange = decodeStart(row);\r
     int[] endRange = decodeEnd(row);\r
 \r
+    StringBuffer result = new StringBuffer(20);\r
     decodeMiddle(row, startRange[1], endRange[0], result);\r
-\r
     String resultString = result.toString();\r
 \r
-    int[] allowedLengths = (int[]) hints.get(DecodeHintType.ALLOWED_LENGTHS);\r
+    int[] allowedLengths = null;\r
+    if (hints != null) {\r
+      allowedLengths = (int[]) hints.get(DecodeHintType.ALLOWED_LENGTHS);\r
+\r
+    }\r
     if (allowedLengths == null) {\r
       allowedLengths = DEFAULT_ALLOWED_LENGTHS;\r
     }\r
@@ -105,14 +107,14 @@ public final class ITFReader extends AbstractOneDReader {
 \r
     }\r
     if (!lengthOK) {\r
-      throw ReaderException.getInstance();\r
+      throw FormatException.getFormatInstance();\r
     }\r
 \r
     return new Result(\r
         resultString,\r
         null, // no natural byte representation for these barcodes\r
-        new ResultPoint[] { new GenericResultPoint(startRange[1], (float) rowNumber),\r
-                            new GenericResultPoint(startRange[0], (float) rowNumber)},\r
+        new ResultPoint[] { new ResultPoint(startRange[1], (float) rowNumber),\r
+                            new ResultPoint(endRange[0], (float) rowNumber)},\r
         BarcodeFormat.ITF);\r
   }\r
 \r
@@ -120,9 +122,10 @@ public final class ITFReader extends AbstractOneDReader {
    * @param row          row of black/white values to search\r
    * @param payloadStart offset of start pattern\r
    * @param resultString {@link StringBuffer} to append decoded chars to\r
-   * @throws ReaderException if decoding could not complete successfully\r
+   * @throws NotFoundException if decoding could not complete successfully\r
    */\r
-  static void decodeMiddle(BitArray row, int payloadStart, int payloadEnd, StringBuffer resultString) throws ReaderException {\r
+  private static void decodeMiddle(BitArray row, int payloadStart, int payloadEnd,\r
+      StringBuffer resultString) throws NotFoundException {\r
 \r
     // Digits are interleaved in pairs - 5 black lines for one digit, and the\r
     // 5\r
@@ -161,9 +164,9 @@ public final class ITFReader extends AbstractOneDReader {
    * @param row row of black/white values to search\r
    * @return Array, containing index of start of 'start block' and end of\r
    *         'start block'\r
-   * @throws ReaderException\r
+   * @throws NotFoundException\r
    */\r
-  int[] decodeStart(BitArray row) throws ReaderException {\r
+  int[] decodeStart(BitArray row) throws NotFoundException {\r
     int endStart = skipWhiteSpace(row);\r
     int[] startPattern = findGuardPattern(row, endStart, START_PATTERN);\r
 \r
@@ -190,9 +193,9 @@ public final class ITFReader extends AbstractOneDReader {
    *\r
    * @param row bit array representing the scanned barcode.\r
    * @param startPattern index into row of the start or end pattern.\r
-   * @throws ReaderException if the quiet zone cannot be found, a ReaderException is thrown.\r
+   * @throws NotFoundException if the quiet zone cannot be found, a ReaderException is thrown.\r
    */\r
-  private void validateQuietZone(BitArray row, int startPattern) throws ReaderException {\r
+  private void validateQuietZone(BitArray row, int startPattern) throws NotFoundException {\r
 \r
     int quietCount = this.narrowLineWidth * 10;  // expect to find this many pixels of quiet zone\r
 \r
@@ -204,7 +207,7 @@ public final class ITFReader extends AbstractOneDReader {
     }\r
     if (quietCount != 0) {\r
       // Unable to find the necessary number of quiet zone pixels.\r
-      throw ReaderException.getInstance();\r
+      throw NotFoundException.getNotFoundInstance();\r
     }\r
   }\r
 \r
@@ -213,9 +216,9 @@ public final class ITFReader extends AbstractOneDReader {
    *\r
    * @param row row of black/white values to search\r
    * @return index of the first black line.\r
-   * @throws ReaderException Throws exception if no black lines are found in the row\r
+   * @throws NotFoundException Throws exception if no black lines are found in the row\r
    */\r
-  private static int skipWhiteSpace(BitArray row) throws ReaderException {\r
+  private static int skipWhiteSpace(BitArray row) throws NotFoundException {\r
     int width = row.getSize();\r
     int endStart = 0;\r
     while (endStart < width) {\r
@@ -225,7 +228,7 @@ public final class ITFReader extends AbstractOneDReader {
       endStart++;\r
     }\r
     if (endStart == width) {\r
-      throw ReaderException.getInstance();\r
+      throw NotFoundException.getNotFoundInstance();\r
     }\r
 \r
     return endStart;\r
@@ -237,40 +240,35 @@ public final class ITFReader extends AbstractOneDReader {
    * @param row row of black/white values to search\r
    * @return Array, containing index of start of 'end block' and end of 'end\r
    *         block'\r
-   * @throws ReaderException\r
+   * @throws NotFoundException\r
    */\r
 \r
-  int[] decodeEnd(BitArray row) throws ReaderException {\r
+  int[] decodeEnd(BitArray row) throws NotFoundException {\r
 \r
     // For convenience, reverse the row and then\r
     // search from 'the start' for the end block\r
     row.reverse();\r
-\r
-    int endStart = skipWhiteSpace(row);\r
-    int[] endPattern;\r
     try {\r
-      endPattern = findGuardPattern(row, endStart, END_PATTERN_REVERSED);\r
-    } catch (ReaderException e) {\r
-      // Put our row of data back the right way before throwing\r
+      int endStart = skipWhiteSpace(row);\r
+      int[] endPattern = findGuardPattern(row, endStart, END_PATTERN_REVERSED);\r
+\r
+      // The start & end patterns must be pre/post fixed by a quiet zone. This\r
+      // zone must be at least 10 times the width of a narrow line.\r
+      // ref: http://www.barcode-1.net/i25code.html\r
+      validateQuietZone(row, endPattern[0]);\r
+\r
+      // Now recalculate the indices of where the 'endblock' starts & stops to\r
+      // accommodate\r
+      // the reversed nature of the search\r
+      int temp = endPattern[0];\r
+      endPattern[0] = row.getSize() - endPattern[1];\r
+      endPattern[1] = row.getSize() - temp;\r
+\r
+      return endPattern;\r
+    } finally {\r
+      // Put the row back the right way.\r
       row.reverse();\r
-      throw e;\r
     }\r
-\r
-    // The start & end patterns must be pre/post fixed by a quiet zone. This\r
-    // zone must be at least 10 times the width of a narrow line.\r
-    // ref: http://www.barcode-1.net/i25code.html\r
-    validateQuietZone(row, endPattern[0]);\r
-\r
-    // Now recalc the indicies of where the 'endblock' starts & stops to\r
-    // accomodate\r
-    // the reversed nature of the search\r
-    int temp = endPattern[0];\r
-    endPattern[0] = row.getSize() - endPattern[1];\r
-    endPattern[1] = row.getSize() - temp;\r
-\r
-    // Put the row back the righ way.\r
-    row.reverse();\r
-    return endPattern;\r
   }\r
 \r
   /**\r
@@ -280,13 +278,12 @@ public final class ITFReader extends AbstractOneDReader {
    *                  being searched for as a pattern\r
    * @return start/end horizontal offset of guard pattern, as an array of two\r
    *         ints\r
-   * @throws ReaderException if pattern is not found\r
+   * @throws NotFoundException if pattern is not found\r
    */\r
-  static int[] findGuardPattern(BitArray row, int rowOffset, int[] pattern) throws ReaderException {\r
-\r
-    // TODO: This is very similar to implementation in AbstractUPCEANReader. Consider if they can be merged to\r
-    // a single method.\r
+  private static int[] findGuardPattern(BitArray row, int rowOffset, int[] pattern) throws NotFoundException {\r
 \r
+    // TODO: This is very similar to implementation in UPCEANReader. Consider if they can be\r
+    // merged to a single method.\r
     int patternLength = pattern.length;\r
     int[] counters = new int[patternLength];\r
     int width = row.getSize();\r
@@ -296,7 +293,7 @@ public final class ITFReader extends AbstractOneDReader {
     int patternStart = rowOffset;\r
     for (int x = rowOffset; x < width; x++) {\r
       boolean pixel = row.get(x);\r
-      if ((!pixel && isWhite) || (pixel && !isWhite)) {\r
+      if (pixel ^ isWhite) {\r
         counters[counterPosition]++;\r
       } else {\r
         if (counterPosition == patternLength - 1) {\r
@@ -317,7 +314,7 @@ public final class ITFReader extends AbstractOneDReader {
         isWhite = !isWhite;\r
       }\r
     }\r
-    throw ReaderException.getInstance();\r
+    throw NotFoundException.getNotFoundInstance();\r
   }\r
 \r
   /**\r
@@ -326,9 +323,9 @@ public final class ITFReader extends AbstractOneDReader {
    *\r
    * @param counters the counts of runs of observed black/white/black/... values\r
    * @return The decoded digit\r
-   * @throws ReaderException if digit cannot be decoded\r
+   * @throws NotFoundException if digit cannot be decoded\r
    */\r
-  private static int decodeDigit(int[] counters) throws ReaderException {\r
+  private static int decodeDigit(int[] counters) throws NotFoundException {\r
 \r
     int bestVariance = MAX_AVG_VARIANCE; // worst variance we'll accept\r
     int bestMatch = -1;\r
@@ -344,8 +341,8 @@ public final class ITFReader extends AbstractOneDReader {
     if (bestMatch >= 0) {\r
       return bestMatch;\r
                } else {\r
-                       throw ReaderException.getInstance();\r
+                       throw NotFoundException.getNotFoundInstance();\r
                }\r
        }\r
 \r
-}
\ No newline at end of file
+}\r