[SCM] Multi-format 1D/2D barcode image processing library branch, upstream, updated. 24d4480bc48cf9eabf7b2bd2f528248b0e458809
srowen
srowen at 59b500cc-1b3d-0410-9834-0bbf25fbcc57
Wed Aug 4 01:32:12 UTC 2010
The following commit has been merged in the upstream branch:
commit 9ceee6853d82d86e881fc3d6d7928ddd47df4cd0
Author: srowen <srowen at 59b500cc-1b3d-0410-9834-0bbf25fbcc57>
Date: Wed Jun 16 19:49:22 2010 +0000
Add support for UPC/EAN +5 extensions, plus basic tests, and display the content in Android client as metadata
git-svn-id: http://zxing.googlecode.com/svn/trunk@1436 59b500cc-1b3d-0410-9834-0bbf25fbcc57
diff --git a/android/res/layout/capture.xml b/android/res/layout/capture.xml
index fd8ab7e..ec5a343 100755
--- a/android/res/layout/capture.xml
+++ b/android/res/layout/capture.xml
@@ -126,6 +126,28 @@
</LinearLayout>
+ <LinearLayout
+ android:orientation="horizontal"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content">
+
+ <TextView android:id="@+id/meta_text_view_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/msg_default_meta"
+ android:textColor="@color/result_minor_text"
+ android:textStyle="bold"
+ android:textSize="14sp"
+ android:paddingRight="4dip"/>
+
+ <TextView android:id="@+id/meta_text_view"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textColor="@color/result_minor_text"
+ android:textSize="14sp"/>
+
+ </LinearLayout>
+
</LinearLayout>
<ScrollView
diff --git a/android/res/values-ar/strings.xml b/android/res/values-ar/strings.xml
index 638ae50..4ded52c 100644
--- a/android/res/values-ar/strings.xml
+++ b/android/res/values-ar/strings.xml
@@ -66,6 +66,7 @@
<string name="msg_default_status">قم بوضع الرمز الشريطي داخل حدود صورة الكاميرا ليتم مسحه.</string>
<string name="msg_default_type">النوع</string>
<string name="msg_default_time">الوقت</string>
+ <string name="msg_default_meta">البيانات الوصفية</string>
<string name="msg_encode_barcode_failed">تعذر إنشاء الرمز الشريطي المطلوب.</string>
<string name="msg_encode_contents_failed">تعذر ترميز رمز شريطي من البيانات المتوفرة.</string>
<string name="msg_encode_in_progress">إنشاء رمز شريطي...</string>
diff --git a/android/res/values-cs/strings.xml b/android/res/values-cs/strings.xml
index b51ec57..61cad4f 100644
--- a/android/res/values-cs/strings.xml
+++ b/android/res/values-cs/strings.xml
@@ -65,7 +65,8 @@
<string name="msg_default_mms_subject">Ahoj</string>
<string name="msg_default_status">Strefte se čtverečkem na čárový kód</string>
<string name="msg_default_type">Typ</string>
- <string name="msg_default_time">Čas</string>
+ <string name="msg_default_time">Čas</string>
+ <string name="msg_default_meta">Metadata</string>
<string name="msg_encode_barcode_failed">Nepodařilo se vytvořit požadovaný čárový kód.</string>
<string name="msg_encode_contents_failed">Nepodařilo se rozkódovat čárový kód z poskytnutých údajů.</string>
<string name="msg_encode_in_progress">Generování kódu\u2026</string>
diff --git a/android/res/values-da/strings.xml b/android/res/values-da/strings.xml
index 54e331b..43c43a7 100644
--- a/android/res/values-da/strings.xml
+++ b/android/res/values-da/strings.xml
@@ -66,6 +66,7 @@
<string name="msg_default_status">Peg på en stregkode så den er inde i firkanten for at scanne den.</string>
<string name="msg_default_type">Type</string>
<string name="msg_default_time">Tid</string>
+ <string name="msg_default_meta">Metadata</string>
<string name="msg_encode_barcode_failed">Kunne ikke generere den ønskede stregkode.</string>
<string name="msg_encode_contents_failed">Kunne ikke indkode en stregkode fra oplysningerne.</string>
<string name="msg_encode_in_progress">Genererer en stregkode\u2026</string>
diff --git a/android/res/values-de/strings.xml b/android/res/values-de/strings.xml
index 5e8d7fe..8e9fcd2 100644
--- a/android/res/values-de/strings.xml
+++ b/android/res/values-de/strings.xml
@@ -65,7 +65,8 @@
<string name="msg_default_mms_subject">Hi</string>
<string name="msg_default_status">Positionieren Sie den Barcode innerhalb des Rechteckes.</string>
<string name="msg_default_type">Typ</string>
- <string name="msg_default_time">Zeit</string>
+ <string name="msg_default_time">Zeit</string>
+ <string name="msg_default_meta">Metadata</string>
<string name="msg_encode_barcode_failed">Der gewünschte Barcode kann nicht erzeugt werden.</string>
<string name="msg_encode_contents_failed">Aus den Daten kann kein Barcode erzeugt werden.</string>
<string name="msg_encode_in_progress">Erzeuge Barcode\u2026</string>
diff --git a/android/res/values-es/strings.xml b/android/res/values-es/strings.xml
index bf59661..169828d 100644
--- a/android/res/values-es/strings.xml
+++ b/android/res/values-es/strings.xml
@@ -65,7 +65,8 @@
<string name="msg_default_mms_subject">Hola</string>
<string name="msg_default_status">Coloque un código de barras en el interior del rectángulo de el visor para escanear.</string>
<string name="msg_default_type">Tipo</string>
- <string name="msg_default_time">Tiempo</string>
+ <string name="msg_default_time">Tiempo</string>
+ <string name="msg_default_meta">Metadata</string>
<string name="msg_encode_barcode_failed">No se pudo generar el código de barras solicitado.</string>
<string name="msg_encode_contents_failed">No puede codificar un código de barras con estos datos.</string>
<string name="msg_encode_in_progress">Generando un código de barras\u2026</string>
diff --git a/android/res/values-fi/strings.xml b/android/res/values-fi/strings.xml
index 9a54420..874d579 100644
--- a/android/res/values-fi/strings.xml
+++ b/android/res/values-fi/strings.xml
@@ -65,7 +65,8 @@
<string name="msg_default_mms_subject">Hei</string>
<string name="msg_default_status">Aseta viivakoodi neliön sisälle.</string>
<string name="msg_default_type">Tyypi</string>
- <string name="msg_default_time">Aika</string>
+ <string name="msg_default_time">Aika</string>
+ <string name="msg_default_meta">Metadata</string>
<string name="msg_encode_barcode_failed">Ei voinut generoida pyydettyä viivakoodia.</string>
<string name="msg_encode_contents_failed">Ei voinut purkaa viivakoodin sisältöä.</string>
<string name="msg_encode_in_progress">Generoidaan viivakoodia\u2026</string>
diff --git a/android/res/values-fr/strings.xml b/android/res/values-fr/strings.xml
index dcf012e..1dca67b 100644
--- a/android/res/values-fr/strings.xml
+++ b/android/res/values-fr/strings.xml
@@ -65,7 +65,8 @@
<string name="msg_default_mms_subject">Salut</string>
<string name="msg_default_status">Mettre un code barre à l\'intérieur du rectangle pour le scanner.</string>
<string name="msg_default_type">Type</string>
- <string name="msg_default_time">Temps</string>
+ <string name="msg_default_time">Temps</string>
+ <string name="msg_default_meta">Métadonnées</string>
<string name="msg_encode_barcode_failed">Impossible de générer le code barre demandé.</string>
<string name="msg_encode_contents_failed">Impossible de créer le code barre à partir des données fournies.</string>
<string name="msg_encode_in_progress">Génération du code barre\u2026</string>
diff --git a/android/res/values-hu/strings.xml b/android/res/values-hu/strings.xml
index 25622cd..e0d0125 100644
--- a/android/res/values-hu/strings.xml
+++ b/android/res/values-hu/strings.xml
@@ -68,7 +68,8 @@
<string name="msg_default_mms_subject">Szia</string>
<string name="msg_default_status">Helyezze a vonalkódot a kereső téglalapba a szkenneléshez.</string>
<string name="msg_default_type">Típus</string>
- <string name="msg_default_time">Idő</string>
+ <string name="msg_default_time">Idő</string>
+ <string name="msg_default_meta">Metaadatok</string>
<string name="msg_encode_barcode_failed">Nem lehetett legenerálni a kért vonalkódot.</string>
<string name="msg_encode_contents_failed">Nem lehetett lekódolni a vonalkódot a megadott tartalomból.</string>
<string name="msg_encode_in_progress">Vonalkód generálása\u2026</string>
diff --git a/android/res/values-it/strings.xml b/android/res/values-it/strings.xml
index a2a8851..9f618fa 100644
--- a/android/res/values-it/strings.xml
+++ b/android/res/values-it/strings.xml
@@ -66,6 +66,7 @@
<string name="msg_default_status">Posiziona un codice a barre dentro il mirino rettangolare per la scansione.</string>
<string name="msg_default_type">Tipo</string>
<string name="msg_default_time">Tempo</string>
+ <string name="msg_default_meta">Metadati</string>
<string name="msg_encode_barcode_failed">Impossibile generare il codice a barre richiesto.</string>
<string name="msg_encode_contents_failed">Impossibile codificare un codice a barre dai dati forniti.</string>
<string name="msg_encode_in_progress">Generazione codice a barre\u2026</string>
diff --git a/android/res/values-ja-rJP/strings.xml b/android/res/values-ja-rJP/strings.xml
index e126b16..105287b 100644
--- a/android/res/values-ja-rJP/strings.xml
+++ b/android/res/values-ja-rJP/strings.xml
@@ -66,6 +66,7 @@
<string name="msg_default_status">バーコードをカメラ画面の読み取り範囲内に写してスキャンしてください。</string>
<string name="msg_default_type">タイプ</string>
<string name="msg_default_time">時間</string>
+ <string name="msg_default_meta">メタデータ</string>
<string name="msg_encode_barcode_failed">バーコードを作成できませんでした。</string>
<string name="msg_encode_contents_failed">このデータからバーコードを作成できませんでした。</string>
<string name="msg_encode_in_progress">バーコード作成中\u2026</string>
diff --git a/android/res/values-nl/strings.xml b/android/res/values-nl/strings.xml
index 69d6f55..0584ab9 100644
--- a/android/res/values-nl/strings.xml
+++ b/android/res/values-nl/strings.xml
@@ -66,6 +66,7 @@
<string name="msg_default_status">Plaats een barcode binnen de rechthoek om hem te scannen.</string>
<string name="msg_default_type">Type</string>
<string name="msg_default_time">Tijd</string>
+ <string name="msg_default_meta">Metadata</string>
<string name="msg_encode_barcode_failed">Kan de gevraagde barcode niet genereren.</string>
<string name="msg_encode_contents_failed">Kan geen barcode van de gegeven data maken.</string>
<string name="msg_encode_in_progress">Barcode aan het genereren\u2026</string>
diff --git a/android/res/values-pl/strings.xml b/android/res/values-pl/strings.xml
index 616e561..90dd961 100644
--- a/android/res/values-pl/strings.xml
+++ b/android/res/values-pl/strings.xml
@@ -66,6 +66,7 @@
<string name="msg_default_status">Umieść kod paskowy w prostokącie wizjera aby zeskanować.</string>
<string name="msg_default_type">Typ</string>
<string name="msg_default_time">Czas</string>
+ <string name="msg_default_meta">Metadanych</string>
<string name="msg_encode_barcode_failed">Nie można wygenerować żądanego kodu paskowego.</string>
<string name="msg_encode_contents_failed">Nie można zakodować kodu paskowego z dostarczonych danych.</string>
<string name="msg_encode_in_progress">Generowanie kodu paskowego\u2026</string>
diff --git a/android/res/values-pt/strings.xml b/android/res/values-pt/strings.xml
index 8bed877..656b2d6 100644
--- a/android/res/values-pt/strings.xml
+++ b/android/res/values-pt/strings.xml
@@ -66,6 +66,7 @@
<string name="msg_default_status">Coloque um código de barras dentro do retângulo do visor para verificar isso.</string>
<string name="msg_default_type">Tipo</string>
<string name="msg_default_time">Tempo</string>
+ <string name="msg_default_meta">Metadados</string>
<string name="msg_encode_barcode_failed">Não foi possível criar código de barras pedido.</string>
<string name="msg_encode_contents_failed">Não foi possível codificar código de barras dos dados fornecidos.</string>
<string name="msg_encode_in_progress">A gerar código de barras\u2026</string>
diff --git a/android/res/values-ru/strings.xml b/android/res/values-ru/strings.xml
index b2a41ee..31f4e7f 100644
--- a/android/res/values-ru/strings.xml
+++ b/android/res/values-ru/strings.xml
@@ -66,6 +66,7 @@
<string name="msg_default_status">Чтобы сканировать штрих-код, поместите его в прямоугольник видоискателя.</string>
<string name="msg_default_type">Тип</string>
<string name="msg_default_time">Время</string>
+ <string name="msg_default_meta">Метаданные</string>
<string name="msg_encode_barcode_failed">Не получилось сгенерировать запрошенный штрих-код.</string>
<string name="msg_encode_contents_failed">Не могу закодировать штрих-код от источник данных.</string>
<string name="msg_encode_in_progress">Генерация штрих-кода\u2026</string>
diff --git a/android/res/values-sv/strings.xml b/android/res/values-sv/strings.xml
index 29e5159..9a3ca1b 100644
--- a/android/res/values-sv/strings.xml
+++ b/android/res/values-sv/strings.xml
@@ -66,6 +66,7 @@
<string name="msg_default_status">Placera steckkoden inom sökarens rektangel för att läsa den.</string>
<string name="msg_default_type">Typ</string>
<string name="msg_default_time">Tid</string>
+ <string name="msg_default_meta">Metadata</string>
<string name="msg_encode_barcode_failed">Misslyckades med att skapa den önskade streckkoden.</string>
<string name="msg_encode_contents_failed">Kunde inte skape en streckkod från de givna uppgifterna.</string>
<string name="msg_encode_in_progress">Genererar en streckkod\u2026</string>
diff --git a/android/res/values-zh-rCN/strings.xml b/android/res/values-zh-rCN/strings.xml
index 1f9c008..1b727b6 100644
--- a/android/res/values-zh-rCN/strings.xml
+++ b/android/res/values-zh-rCN/strings.xml
@@ -66,6 +66,7 @@
<string name="msg_default_status">将条码放置于镜头范围内进行扫描。 </string>
<string name="msg_default_type">类型</string>
<string name="msg_default_time">时间</string>
+ <string name="msg_default_meta">元数据</string>
<string name="msg_encode_barcode_failed">找不到条码。</string>
<string name="msg_encode_contents_failed">不能从已有数据中读取条码。 </string>
<string name="msg_encode_in_progress">正在生成条码\u2026</string>
diff --git a/android/res/values-zh-rTW/strings.xml b/android/res/values-zh-rTW/strings.xml
index abba6a4..15caf0a 100644
--- a/android/res/values-zh-rTW/strings.xml
+++ b/android/res/values-zh-rTW/strings.xml
@@ -66,6 +66,7 @@
<string name="msg_default_status">將條碼放置於鏡頭範圍內進行掃描。 </string>
<string name="msg_default_type">類型</string>
<string name="msg_default_time">時間</string>
+ <string name="msg_default_meta">元數據</string>
<string name="msg_encode_barcode_failed">找不到條碼。</string>
<string name="msg_encode_contents_failed">無法讀取條碼。 </string>
<string name="msg_encode_in_progress">正在產生條碼\u2026</string>
diff --git a/android/res/values/strings.xml b/android/res/values/strings.xml
index 94a3fa8..8b37e2a 100755
--- a/android/res/values/strings.xml
+++ b/android/res/values/strings.xml
@@ -63,6 +63,7 @@
<string name="msg_default_contents">Contents</string>
<string name="msg_default_format">Format</string>
<string name="msg_default_mms_subject">Hi</string>
+ <string name="msg_default_meta">Metadata</string>
<string name="msg_default_status">Place a barcode inside the viewfinder rectangle to scan it.</string>
<string name="msg_default_type">Type</string>
<string name="msg_default_time">Time</string>
diff --git a/android/src/com/google/zxing/client/android/CaptureActivity.java b/android/src/com/google/zxing/client/android/CaptureActivity.java
index 13323d3..fbdb29d 100755
--- a/android/src/com/google/zxing/client/android/CaptureActivity.java
+++ b/android/src/com/google/zxing/client/android/CaptureActivity.java
@@ -19,6 +19,7 @@ package com.google.zxing.client.android;
import android.util.TypedValue;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.Result;
+import com.google.zxing.ResultMetadataType;
import com.google.zxing.ResultPoint;
import com.google.zxing.client.android.camera.CameraManager;
import com.google.zxing.client.android.history.HistoryManager;
@@ -66,8 +67,12 @@ import android.widget.TextView;
import java.io.IOException;
import java.text.DateFormat;
import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Hashtable;
import java.util.List;
import java.util.Date;
+import java.util.Map;
+import java.util.Set;
import java.util.Vector;
import java.util.regex.Pattern;
@@ -125,6 +130,14 @@ public final class CaptureActivity extends Activity implements SurfaceHolder.Cal
ALL_FORMATS.addAll(QR_CODE_FORMATS);
}
+ private static final Set<ResultMetadataType> DISPLAYABLE_METADATA_TYPES;
+ static {
+ DISPLAYABLE_METADATA_TYPES = new HashSet<ResultMetadataType>(3);
+ DISPLAYABLE_METADATA_TYPES.add(ResultMetadataType.ISSUE_NUMBER);
+ DISPLAYABLE_METADATA_TYPES.add(ResultMetadataType.SUGGESTED_PRICE);
+ DISPLAYABLE_METADATA_TYPES.add(ResultMetadataType.ERROR_CORRECTION_LEVEL);
+ }
+
private enum Source {
NATIVE_APP_INTENT,
PRODUCT_SEARCH_LINK,
@@ -504,20 +517,39 @@ public final class CaptureActivity extends Activity implements SurfaceHolder.Cal
barcodeImageView.setVisibility(View.VISIBLE);
TextView formatTextView = (TextView) findViewById(R.id.format_text_view);
- formatTextView.setVisibility(View.VISIBLE);
formatTextView.setText(rawResult.getBarcodeFormat().toString());
ResultHandler resultHandler = ResultHandlerFactory.makeResultHandler(this, rawResult);
TextView typeTextView = (TextView) findViewById(R.id.type_text_view);
- typeTextView.setVisibility(View.VISIBLE);
typeTextView.setText(resultHandler.getType().toString());
DateFormat formatter = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT);
String formattedTime = formatter.format(new Date(rawResult.getTimestamp()));
TextView timeTextView = (TextView) findViewById(R.id.time_text_view);
- timeTextView.setVisibility(View.VISIBLE);
timeTextView.setText(formattedTime);
+
+ TextView metaTextView = (TextView) findViewById(R.id.meta_text_view);
+ View metaTextViewLabel = findViewById(R.id.meta_text_view_label);
+ metaTextView.setVisibility(View.GONE);
+ metaTextViewLabel.setVisibility(View.GONE);
+ Map<ResultMetadataType,Object> metadata =
+ (Map<ResultMetadataType,Object>) rawResult.getResultMetadata();
+ if (metadata != null) {
+ StringBuilder metadataText = new StringBuilder(20);
+ for (Map.Entry<ResultMetadataType,Object> entry : metadata.entrySet()) {
+ if (DISPLAYABLE_METADATA_TYPES.contains(entry.getKey())) {
+ metadataText.append(entry.getValue()).append('\n');
+ }
+ }
+ if (metadataText.length() > 0) {
+ metadataText.setLength(metadataText.length() - 1);
+ metaTextView.setText(metadataText);
+ metaTextView.setVisibility(View.VISIBLE);
+ metaTextViewLabel.setVisibility(View.VISIBLE);
+ }
+ }
+
TextView contentsTextView = (TextView) findViewById(R.id.contents_text_view);
CharSequence displayContents = resultHandler.getDisplayContents();
contentsTextView.setText(displayContents);
diff --git a/core/src/com/google/zxing/BarcodeFormat.java b/core/src/com/google/zxing/BarcodeFormat.java
index 032a1b6..e10a8a8 100644
--- a/core/src/com/google/zxing/BarcodeFormat.java
+++ b/core/src/com/google/zxing/BarcodeFormat.java
@@ -47,6 +47,9 @@ public final class BarcodeFormat {
/** EAN-13 1D format. */
public static final BarcodeFormat EAN_13 = new BarcodeFormat("EAN_13");
+ /** UPC/EAN extension format. Not a stand-alone format. */
+ public static final BarcodeFormat UPC_EAN_EXTENSION = new BarcodeFormat("UPC_EAN_EXTENSION");
+
/** Code 128 1D format. */
public static final BarcodeFormat CODE_128 = new BarcodeFormat("CODE_128");
@@ -54,9 +57,9 @@ public final class BarcodeFormat {
public static final BarcodeFormat CODE_39 = new BarcodeFormat("CODE_39");
/** Code 93 1D format. */
- public static final BarcodeFormat CODE_93 = new BarcodeFormat("CODE_93");
-
- /** CODABAR 1D format. */
+ public static final BarcodeFormat CODE_93 = new BarcodeFormat("CODE_93");
+
+ /** CODABAR 1D format. */
public static final BarcodeFormat CODABAR = new BarcodeFormat("CODABAR");
/** ITF (Interleaved Two of Five) 1D format. */
diff --git a/core/src/com/google/zxing/Result.java b/core/src/com/google/zxing/Result.java
index ca2edd3..9223ceb 100644
--- a/core/src/com/google/zxing/Result.java
+++ b/core/src/com/google/zxing/Result.java
@@ -16,6 +16,7 @@
package com.google.zxing;
+import java.util.Enumeration;
import java.util.Hashtable;
/**
@@ -101,6 +102,21 @@ public final class Result {
resultMetadata.put(type, value);
}
+ public void putAllMetadata(Hashtable metadata) {
+ if (metadata != null) {
+ if (resultMetadata == null) {
+ resultMetadata = metadata;
+ } else {
+ Enumeration e = metadata.keys();
+ while (e.hasMoreElements()) {
+ ResultMetadataType key = (ResultMetadataType) e.nextElement();
+ Object value = metadata.get(key);
+ resultMetadata.put(key, value);
+ }
+ }
+ }
+ }
+
public long getTimestamp() {
return timestamp;
}
diff --git a/core/src/com/google/zxing/ResultMetadataType.java b/core/src/com/google/zxing/ResultMetadataType.java
index 722b76d..7e47b0e 100644
--- a/core/src/com/google/zxing/ResultMetadataType.java
+++ b/core/src/com/google/zxing/ResultMetadataType.java
@@ -16,6 +16,8 @@
package com.google.zxing;
+import java.util.Hashtable;
+
/**
* Represents some type of metadata about the result of the decoding that the decoder
* wishes to communicate back to the caller.
@@ -26,10 +28,14 @@ public final class ResultMetadataType {
// No, we can't use an enum here. J2ME doesn't support it.
+ private static final Hashtable VALUES = new Hashtable();
+
+ // No, we can't use an enum here. J2ME doesn't support it.
+
/**
* Unspecified, application-specific metadata. Maps to an unspecified {@link Object}.
*/
- public static final ResultMetadataType OTHER = new ResultMetadataType();
+ public static final ResultMetadataType OTHER = new ResultMetadataType("OTHER");
/**
* Denotes the likely approximate orientation of the barcode in the image. This value
@@ -38,7 +44,7 @@ public final class ResultMetadataType {
* said to have orientation "90". This key maps to an {@link Integer} whose
* value is in the range [0,360).
*/
- public static final ResultMetadataType ORIENTATION = new ResultMetadataType();
+ public static final ResultMetadataType ORIENTATION = new ResultMetadataType("ORIENTATION");
/**
* <p>2D barcode formats typically encode text, but allow for a sort of 'byte mode'
@@ -49,15 +55,49 @@ public final class ResultMetadataType {
* <p>This maps to a {@link java.util.Vector} of byte arrays corresponding to the
* raw bytes in the byte segments in the barcode, in order.</p>
*/
- public static final ResultMetadataType BYTE_SEGMENTS = new ResultMetadataType();
+ public static final ResultMetadataType BYTE_SEGMENTS = new ResultMetadataType("BYTE_SEGMENTS");
/**
* Error correction level used, if applicable. The value type depends on the
* format, but is typically a String.
*/
- public static final ResultMetadataType ERROR_CORRECTION_LEVEL = new ResultMetadataType();
+ public static final ResultMetadataType ERROR_CORRECTION_LEVEL = new ResultMetadataType("ERROR_CORRECTION_LEVEL");
+
+ /**
+ * For some periodicals, indicates the issue number as an {@link Integer}.
+ */
+ public static final ResultMetadataType ISSUE_NUMBER = new ResultMetadataType("ISSUE_NUMBER");
+
+ /**
+ * For some products, indicates the suggested retail price in the barcode as a
+ * formatted {@link String}.
+ */
+ public static final ResultMetadataType SUGGESTED_PRICE = new ResultMetadataType("SUGGESTED_PRICE");
+
+ private final String name;
+
+ private ResultMetadataType(String name) {
+ this.name = name;
+ VALUES.put(name, this);
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public String toString() {
+ return name;
+ }
- private ResultMetadataType() {
+ public static ResultMetadataType valueOf(String name) {
+ if (name == null || name.length() == 0) {
+ throw new IllegalArgumentException();
+ }
+ ResultMetadataType format = (ResultMetadataType) VALUES.get(name);
+ if (format == null) {
+ throw new IllegalArgumentException();
+ }
+ return format;
}
}
diff --git a/core/src/com/google/zxing/oned/UPCEANExtensionSupport.java b/core/src/com/google/zxing/oned/UPCEANExtensionSupport.java
new file mode 100644
index 0000000..3076941
--- /dev/null
+++ b/core/src/com/google/zxing/oned/UPCEANExtensionSupport.java
@@ -0,0 +1,189 @@
+/*
+ * Copyright (C) 2010 ZXing authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.zxing.oned;
+
+import java.util.Hashtable;
+
+import com.google.zxing.BarcodeFormat;
+import com.google.zxing.NotFoundException;
+import com.google.zxing.Result;
+import com.google.zxing.ResultMetadataType;
+import com.google.zxing.common.BitArray;
+
+final class UPCEANExtensionSupport {
+
+ private static final int[] EXTENSION_START_PATTERN = {1,1,2};
+ private static final int[] CHECK_DIGIT_ENCODINGS = {
+ 0x18, 0x14, 0x12, 0x11, 0x0C, 0x06, 0x03, 0x0A, 0x09, 0x05
+ };
+ private static final int[][] SEPARATOR_PATTERNS = {{1,1}};
+
+ private final int[] decodeMiddleCounters = new int[4];
+ private final int[] separatorCounters = new int[2];
+ private final StringBuffer decodeRowStringBuffer = new StringBuffer();
+
+ Result decodeRow(BitArray row, int rowOffset) throws NotFoundException {
+
+ int[] extensionStartRange = UPCEANReader.findGuardPattern(row, rowOffset, false, EXTENSION_START_PATTERN);
+
+ StringBuffer result = decodeRowStringBuffer;
+ result.setLength(0);
+ decodeMiddle(row, extensionStartRange, result);
+
+ String resultString = result.toString();
+ Hashtable extensionData = parseExtensionString(resultString);
+
+ Result extensionResult = new Result(resultString, null, null, BarcodeFormat.UPC_EAN_EXTENSION);
+ if (extensionData != null) {
+ extensionResult.putAllMetadata(extensionData);
+ }
+ return extensionResult;
+ }
+
+ int decodeMiddle(BitArray row, int[] startRange, StringBuffer resultString) throws NotFoundException {
+ int[] counters = decodeMiddleCounters;
+ counters[0] = 0;
+ counters[1] = 0;
+ counters[2] = 0;
+ counters[3] = 0;
+ int[] separatorCounters = this.separatorCounters;
+ separatorCounters[0] = 0;
+ separatorCounters[1] = 0;
+ int end = row.getSize();
+ int rowOffset = startRange[1];
+
+ int lgPatternFound = 0;
+
+ for (int x = 0; x < 5 && rowOffset < end; x++) {
+ int bestMatch = UPCEANReader.decodeDigit(row, counters, rowOffset, UPCEANReader.L_AND_G_PATTERNS);
+ resultString.append((char) ('0' + bestMatch % 10));
+ for (int i = 0; i < counters.length; i++) {
+ rowOffset += counters[i];
+ }
+ if (bestMatch >= 10) {
+ lgPatternFound |= 1 << (4 - x);
+ }
+ // Read off separator
+ /*
+ try {
+ UPCEANReader.decodeDigit(row, separatorCounters, rowOffset, SEPARATOR_PATTERNS);
+ rowOffset += separatorCounters[0] + separatorCounters[1];
+ } catch (NotFoundException nfe) {
+ break;
+ }
+ */
+ while (rowOffset < end && !row.get(rowOffset)) {
+ rowOffset++;
+ }
+ while (rowOffset < end && row.get(rowOffset)) {
+ rowOffset++;
+ }
+ }
+
+ if (resultString.length() != 5) {
+ throw NotFoundException.getNotFoundInstance();
+ }
+
+ int checkDigit = determineCheckDigit(lgPatternFound);
+ if (extensionChecksum(resultString.toString()) != checkDigit) {
+ throw NotFoundException.getNotFoundInstance();
+ }
+
+ return rowOffset;
+ }
+
+ private static int extensionChecksum(String s) {
+ int length = s.length();
+ int sum = 0;
+ for (int i = length - 2; i >= 0; i -= 2) {
+ sum += (int) s.charAt(i) - (int) '0';
+ }
+ sum *= 3;
+ for (int i = length - 1; i >= 0; i -= 2) {
+ sum += (int) s.charAt(i) - (int) '0';
+ }
+ sum *= 3;
+ return sum % 10;
+ }
+
+ private static int determineCheckDigit(int lgPatternFound)
+ throws NotFoundException {
+ for (int d = 0; d < 10; d++) {
+ if (lgPatternFound == CHECK_DIGIT_ENCODINGS[d]) {
+ return d;
+ }
+ }
+ throw NotFoundException.getNotFoundInstance();
+ }
+
+ /**
+ * @param raw raw content of extension
+ * @return formatted interpretation of raw content as a {@link Hashtable} mapping
+ * one {@link ResultMetadataType} to appropriate value, or <code>null</code> if not known
+ */
+ private static Hashtable parseExtensionString(String raw) {
+ ResultMetadataType type;
+ Object value;
+ switch (raw.length()) {
+ case 2:
+ type = ResultMetadataType.ISSUE_NUMBER;
+ value = parseExtension2String(raw);
+ break;
+ case 5:
+ type = ResultMetadataType.SUGGESTED_PRICE;
+ value = parseExtension5String(raw);
+ break;
+ default:
+ return null;
+ }
+ if (value == null) {
+ return null;
+ }
+ Hashtable result = new Hashtable(1);
+ result.put(type, value);
+ return result;
+ }
+
+ private static Integer parseExtension2String(String raw) {
+ return Integer.valueOf(raw);
+ }
+
+ private static String parseExtension5String(String raw) {
+ String currency = null;
+ switch (raw.charAt(0)) {
+ case '0':
+ currency = "£";
+ break;
+ case '5':
+ currency = "$";
+ break;
+ case '9':
+ if ("99991".equals(raw)) {
+ return "0.00";
+ } else if ("99990".equals(raw)) {
+ return "Used";
+ }
+ break;
+ default:
+ currency = "";
+ break;
+ }
+ int rawAmount = Integer.parseInt(raw.substring(1));
+ return currency + (rawAmount / 100) + '.' + (rawAmount % 100);
+ }
+
+}
diff --git a/core/src/com/google/zxing/oned/UPCEANReader.java b/core/src/com/google/zxing/oned/UPCEANReader.java
index 803eaa6..6036157 100644
--- a/core/src/com/google/zxing/oned/UPCEANReader.java
+++ b/core/src/com/google/zxing/oned/UPCEANReader.java
@@ -21,6 +21,7 @@ import com.google.zxing.ChecksumException;
import com.google.zxing.DecodeHintType;
import com.google.zxing.FormatException;
import com.google.zxing.NotFoundException;
+import com.google.zxing.ReaderException;
import com.google.zxing.Result;
import com.google.zxing.ResultPoint;
import com.google.zxing.ResultPointCallback;
@@ -91,9 +92,11 @@ public abstract class UPCEANReader extends OneDReader {
}
private final StringBuffer decodeRowStringBuffer;
+ private final UPCEANExtensionSupport extensionReader;
protected UPCEANReader() {
decodeRowStringBuffer = new StringBuffer(20);
+ extensionReader = new UPCEANExtensionSupport();
}
static int[] findStartGuardPattern(BitArray row) throws NotFoundException {
@@ -171,12 +174,20 @@ public abstract class UPCEANReader extends OneDReader {
float left = (float) (startGuardRange[1] + startGuardRange[0]) / 2.0f;
float right = (float) (endRange[1] + endRange[0]) / 2.0f;
- return new Result(resultString,
+ Result decodeResult = new Result(resultString,
null, // no natural byte representation for these barcodes
new ResultPoint[]{
new ResultPoint(left, (float) rowNumber),
new ResultPoint(right, (float) rowNumber)},
getBarcodeFormat());
+
+ try {
+ Result extensionResult = extensionReader.decodeRow(row, endRange[1]);
+ decodeResult.putAllMetadata(extensionResult.getResultMetadata());
+ } catch (ReaderException re) {
+ // continue
+ }
+ return decodeResult;
}
/**
@@ -193,9 +204,8 @@ public abstract class UPCEANReader extends OneDReader {
* @param s string of digits to check
* @return true iff string of digits passes the UPC/EAN checksum algorithm
* @throws FormatException if the string does not contain only digits
- * @throws ChecksumException if checksum mismatches
*/
- private static boolean checkStandardUPCEANChecksum(String s) throws ChecksumException, FormatException {
+ private static boolean checkStandardUPCEANChecksum(String s) throws FormatException {
int length = s.length();
if (length == 0) {
return false;
@@ -213,7 +223,7 @@ public abstract class UPCEANReader extends OneDReader {
for (int i = length - 1; i >= 0; i -= 2) {
int digit = (int) s.charAt(i) - (int) '0';
if (digit < 0 || digit > 9) {
- throw ChecksumException.getChecksumInstance();
+ throw FormatException.getFormatInstance();
}
sum += digit;
}
diff --git a/core/test/data/blackbox/upcean-extension-1/1.gif b/core/test/data/blackbox/upcean-extension-1/1.gif
new file mode 100644
index 0000000..2ef57e0
Binary files /dev/null and b/core/test/data/blackbox/upcean-extension-1/1.gif differ
diff --git a/core/test/data/blackbox/upcean-extension-1/1.metadata.txt b/core/test/data/blackbox/upcean-extension-1/1.metadata.txt
new file mode 100644
index 0000000..6ad3f36
--- /dev/null
+++ b/core/test/data/blackbox/upcean-extension-1/1.metadata.txt
@@ -0,0 +1 @@
+SUGGESTED_PRICE=$12.99
\ No newline at end of file
diff --git a/core/test/data/blackbox/upcean-extension-1/1.txt b/core/test/data/blackbox/upcean-extension-1/1.txt
new file mode 100644
index 0000000..101471a
--- /dev/null
+++ b/core/test/data/blackbox/upcean-extension-1/1.txt
@@ -0,0 +1 @@
+9780735200449
\ No newline at end of file
diff --git a/core/test/data/blackbox/upcean-extension-1/2.jpg b/core/test/data/blackbox/upcean-extension-1/2.jpg
new file mode 100755
index 0000000..b716cce
Binary files /dev/null and b/core/test/data/blackbox/upcean-extension-1/2.jpg differ
diff --git a/core/test/data/blackbox/upcean-extension-1/2.metadata.txt b/core/test/data/blackbox/upcean-extension-1/2.metadata.txt
new file mode 100644
index 0000000..e14808d
--- /dev/null
+++ b/core/test/data/blackbox/upcean-extension-1/2.metadata.txt
@@ -0,0 +1 @@
+SUGGESTED_PRICE=$24.95
\ No newline at end of file
diff --git a/core/test/data/blackbox/upcean-extension-1/2.txt b/core/test/data/blackbox/upcean-extension-1/2.txt
new file mode 100644
index 0000000..576a811
--- /dev/null
+++ b/core/test/data/blackbox/upcean-extension-1/2.txt
@@ -0,0 +1 @@
+9780884271789
\ No newline at end of file
diff --git a/core/test/src/com/google/zxing/common/AbstractBlackBoxTestCase.java b/core/test/src/com/google/zxing/common/AbstractBlackBoxTestCase.java
index d078fa1..5048343 100644
--- a/core/test/src/com/google/zxing/common/AbstractBlackBoxTestCase.java
+++ b/core/test/src/com/google/zxing/common/AbstractBlackBoxTestCase.java
@@ -23,6 +23,7 @@ import com.google.zxing.LuminanceSource;
import com.google.zxing.Reader;
import com.google.zxing.ReaderException;
import com.google.zxing.Result;
+import com.google.zxing.ResultMetadataType;
import com.google.zxing.client.j2se.BufferedImageLuminanceSource;
import junit.framework.TestCase;
@@ -40,6 +41,8 @@ import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.List;
+import java.util.Map;
+import java.util.Properties;
/**
* @author Sean Owen
@@ -174,19 +177,25 @@ public abstract class AbstractBlackBoxTestCase extends TestCase {
BufferedImage image = ImageIO.read(testImage);
String testImageFileName = testImage.getName();
- File expectedTextFile = new File(testBase,
- testImageFileName.substring(0, testImageFileName.indexOf('.')) + ".txt");
+ String fileBaseName = testImageFileName.substring(0, testImageFileName.indexOf('.'));
+ File expectedTextFile = new File(testBase, fileBaseName + ".txt");
String expectedText = readFileAsString(expectedTextFile);
+ File expectedMetadataFile = new File(testBase, fileBaseName + ".metadata.txt");
+ Properties expectedMetadata = new Properties();
+ if (expectedMetadataFile.exists()) {
+ expectedMetadata.load(new FileInputStream(expectedMetadataFile));
+ }
+
for (int x = 0; x < testCount; x++) {
float rotation = testResults.get(x).getRotation();
BufferedImage rotatedImage = rotateImage(image, rotation);
LuminanceSource source = new BufferedImageLuminanceSource(rotatedImage);
BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
- if (decode(bitmap, rotation, expectedText, false)) {
+ if (decode(bitmap, rotation, expectedText, expectedMetadata, false)) {
passedCounts[x]++;
}
- if (decode(bitmap, rotation, expectedText, true)) {
+ if (decode(bitmap, rotation, expectedText, expectedMetadata, true)) {
tryHarderCounts[x]++;
}
}
@@ -231,7 +240,10 @@ public abstract class AbstractBlackBoxTestCase extends TestCase {
return new SummaryResults(totalFound, totalMustPass, totalTests);
}
- private boolean decode(BinaryBitmap source, float rotation, String expectedText,
+ private boolean decode(BinaryBitmap source,
+ float rotation,
+ String expectedText,
+ Properties expectedMetadata,
boolean tryHarder) {
Result result;
String suffix = " (" + (tryHarder ? "try harder, " : "") + "rotation: " + rotation + ')';
@@ -263,6 +275,19 @@ public abstract class AbstractBlackBoxTestCase extends TestCase {
'\'' + suffix);
return false;
}
+
+ Hashtable resultMetadata = result.getResultMetadata();
+ for (Map.Entry<Object,Object> metadatum : expectedMetadata.entrySet()) {
+ ResultMetadataType key = ResultMetadataType.valueOf(metadatum.getKey().toString());
+ Object expectedValue = metadatum.getValue();
+ Object actualValue = resultMetadata == null ? null : resultMetadata.get(key);
+ if (!expectedValue.equals(actualValue)) {
+ System.out.println("Metadata mismatch: for key '" + key + "' expected '" + expectedValue +
+ "' but got '" + actualValue + '\'');
+ return false;
+ }
+ }
+
return true;
}
diff --git a/core/test/src/com/google/zxing/oned/Code128BlackBox3TestCase.java b/core/test/src/com/google/zxing/oned/UPCEANExtensionBlackBox1TestCase.java
similarity index 77%
copy from core/test/src/com/google/zxing/oned/Code128BlackBox3TestCase.java
copy to core/test/src/com/google/zxing/oned/UPCEANExtensionBlackBox1TestCase.java
index 72f52ff..e1a5acf 100644
--- a/core/test/src/com/google/zxing/oned/Code128BlackBox3TestCase.java
+++ b/core/test/src/com/google/zxing/oned/UPCEANExtensionBlackBox1TestCase.java
@@ -23,12 +23,11 @@ import com.google.zxing.common.AbstractBlackBoxTestCase;
/**
* @author Sean Owen
*/
-public final class Code128BlackBox3TestCase extends AbstractBlackBoxTestCase {
+public final class UPCEANExtensionBlackBox1TestCase extends AbstractBlackBoxTestCase {
- public Code128BlackBox3TestCase() {
- super("test/data/blackbox/code128-3", new MultiFormatReader(), BarcodeFormat.CODE_128);
+ public UPCEANExtensionBlackBox1TestCase() {
+ super("test/data/blackbox/upcean-extension-1", new MultiFormatReader(), BarcodeFormat.EAN_13);
addTest(2, 2, 0.0f);
- addTest(2, 2, 180.0f);
}
}
\ No newline at end of file
--
Multi-format 1D/2D barcode image processing library
More information about the Pkg-google-commits
mailing list