More encoding related changes for encoding Chinese chars in QR codes
authorsrowen <srowen@59b500cc-1b3d-0410-9834-0bbf25fbcc57>
Thu, 27 May 2010 11:25:00 +0000 (11:25 +0000)
committersrowen <srowen@59b500cc-1b3d-0410-9834-0bbf25fbcc57>
Thu, 27 May 2010 11:25:00 +0000 (11:25 +0000)
git-svn-id: http://zxing.googlecode.com/svn/trunk@1392 59b500cc-1b3d-0410-9834-0bbf25fbcc57

android/src/com/google/zxing/client/android/encode/EncodeThread.java [new file with mode: 0644]
android/src/com/google/zxing/client/android/encode/QRCodeEncoder.java
core/src/com/google/zxing/client/result/VCardResultParser.java

diff --git a/android/src/com/google/zxing/client/android/encode/EncodeThread.java b/android/src/com/google/zxing/client/android/encode/EncodeThread.java
new file mode 100644 (file)
index 0000000..02477f5
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * 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.client.android.encode;
+
+import android.graphics.Bitmap;
+import android.os.Handler;
+import android.os.Message;
+import android.util.Log;
+import com.google.zxing.BarcodeFormat;
+import com.google.zxing.WriterException;
+import com.google.zxing.client.android.R;
+
+final class EncodeThread extends Thread {
+
+  private static final String TAG = EncodeThread.class.getSimpleName();
+
+  private final String contents;
+  private final Handler handler;
+  private final int pixelResolution;
+  private final BarcodeFormat format;
+
+  EncodeThread(String contents, Handler handler, int pixelResolution, BarcodeFormat format) {
+    this.contents = contents;
+    this.handler = handler;
+    this.pixelResolution = pixelResolution;
+    this.format = format;
+  }
+
+  @Override
+  public void run() {
+    try {
+      Bitmap bitmap = QRCodeEncoder.encodeAsBitmap(contents, format, pixelResolution, pixelResolution);
+      Message message = Message.obtain(handler, R.id.encode_succeeded);
+      message.obj = bitmap;
+      message.sendToTarget();
+    } catch (WriterException e) {
+      Log.e(TAG, "Could not encode barcode", e);
+      Message message = Message.obtain(handler, R.id.encode_failed);
+      message.sendToTarget();
+    } catch (IllegalArgumentException e) {
+      Log.e(TAG, "Could not encode barcode", e);
+      Message message = Message.obtain(handler, R.id.encode_failed);
+      message.sendToTarget();
+    }
+  }
+}
index 358795d..2a13011 100755 (executable)
@@ -17,6 +17,7 @@
 package com.google.zxing.client.android.encode;
 
 import com.google.zxing.BarcodeFormat;
+import com.google.zxing.EncodeHintType;
 import com.google.zxing.MultiFormatWriter;
 import com.google.zxing.Result;
 import com.google.zxing.WriterException;
@@ -34,7 +35,6 @@ import android.graphics.Bitmap;
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.Handler;
-import android.os.Message;
 import android.provider.Contacts;
 import android.telephony.PhoneNumberUtils;
 import android.util.Log;
@@ -42,6 +42,7 @@ import android.util.Log;
 import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.InputStream;
+import java.util.Hashtable;
 
 /**
  * This class does the work of decoding the user's request and extracting all the data
@@ -308,8 +309,14 @@ final class QRCodeEncoder {
                                BarcodeFormat format,
                                int desiredWidth,
                                int desiredHeight) throws WriterException {
-    BitMatrix result = new MultiFormatWriter().encode(contents, format,
-        desiredWidth, desiredHeight);
+    Hashtable hints = null;
+    String encoding = guessAppropriateEncoding(contents);
+    if (encoding != null) {
+      hints = new Hashtable(2);
+      hints.put(EncodeHintType.CHARACTER_SET, encoding);
+    }
+    MultiFormatWriter writer = new MultiFormatWriter();    
+    BitMatrix result = writer.encode(contents, format, desiredWidth, desiredHeight, hints);
     int width = result.getWidth();
     int height = result.getHeight();
     int[] pixels = new int[width * height];
@@ -326,39 +333,13 @@ final class QRCodeEncoder {
     return bitmap;
   }
 
-  private static final class EncodeThread extends Thread {
-
-    private static final String TAG = EncodeThread.class.getSimpleName();
-
-    private final String contents;
-    private final Handler handler;
-    private final int pixelResolution;
-    private final BarcodeFormat format;
-
-    EncodeThread(String contents, Handler handler, int pixelResolution,
-        BarcodeFormat format) {
-      this.contents = contents;
-      this.handler = handler;
-      this.pixelResolution = pixelResolution;
-      this.format = format;
-    }
-
-    @Override
-    public void run() {
-      try {
-        Bitmap bitmap = encodeAsBitmap(contents, format, pixelResolution, pixelResolution);
-        Message message = Message.obtain(handler, R.id.encode_succeeded);
-        message.obj = bitmap;
-        message.sendToTarget();
-      } catch (WriterException e) {
-        Log.e(TAG, "Could not encode barcode", e);
-        Message message = Message.obtain(handler, R.id.encode_failed);
-        message.sendToTarget();
-      } catch (IllegalArgumentException e) {
-        Log.e(TAG, "Could not encode barcode", e);
-        Message message = Message.obtain(handler, R.id.encode_failed);
-        message.sendToTarget();
+  private static String guessAppropriateEncoding(CharSequence contents) {
+    // Very crude at the moment
+    for (int i = 0; i < contents.length(); i++) {
+      if (contents.charAt(i) > 0xFF) {
+        return "UTF-8";
       }
     }
+    return null;
   }
 }
index 4e32ba8..4d53971 100644 (file)
@@ -18,6 +18,8 @@ package com.google.zxing.client.result;
 
 import com.google.zxing.Result;
 
+import java.io.ByteArrayOutputStream;
+import java.io.UnsupportedEncodingException;
 import java.util.Vector;
 
 /**
@@ -93,6 +95,7 @@ final class VCardResultParser extends ResultParser {
       }
 
       boolean quotedPrintable = false;
+      String quotedPrintableCharset = null;
       if (i > metadataStart) {
         // There was something after the tag, before colon
         int j = metadataStart+1;
@@ -107,6 +110,8 @@ final class VCardResultParser extends ResultParser {
                 if (value.equalsIgnoreCase("QUOTED-PRINTABLE")) {
                   quotedPrintable = true;
                 }
+              } else if (key.equalsIgnoreCase("CHARSET")) {
+                quotedPrintableCharset = value;
               }
             }
             metadataStart = j;
@@ -149,7 +154,7 @@ final class VCardResultParser extends ResultParser {
           element = element.trim();
         }
         if (quotedPrintable) {
-          element = decodeQuotedPrintable(element);
+          element = decodeQuotedPrintable(element, quotedPrintableCharset);
         } else {
           element = stripContinuationCRLF(element);
         }
@@ -191,9 +196,10 @@ final class VCardResultParser extends ResultParser {
     return result.toString();
   }
 
-  private static String decodeQuotedPrintable(String value) {
+  private static String decodeQuotedPrintable(String value, String charset) {
     int length = value.length();
     StringBuffer result = new StringBuffer(length);
+    ByteArrayOutputStream fragmentBuffer = new ByteArrayOutputStream();
     for (int i = 0; i < length; i++) {
       char c = value.charAt(i);
       switch (c) {
@@ -208,8 +214,8 @@ final class VCardResultParser extends ResultParser {
             } else {
               char nextNextChar = value.charAt(i+2);
               try {
-                int encodedChar = 16 * toHexValue(nextChar) + toHexValue(nextNextChar);
-                result.append((char) encodedChar);
+                int encodedByte = 16 * toHexValue(nextChar) + toHexValue(nextNextChar);
+                fragmentBuffer.write(encodedByte);
               } catch (IllegalArgumentException iae) {
                 // continue, assume it was incorrectly encoded
               }
@@ -218,9 +224,11 @@ final class VCardResultParser extends ResultParser {
           }
           break;
         default:
+          maybeAppendFragment(fragmentBuffer, charset, result);
           result.append(c);
       }
     }
+    maybeAppendFragment(fragmentBuffer, charset, result);
     return result.toString();
   }
 
@@ -235,6 +243,27 @@ final class VCardResultParser extends ResultParser {
     throw new IllegalArgumentException();
   }
 
+  private static void maybeAppendFragment(ByteArrayOutputStream fragmentBuffer,
+                                          String charset,
+                                          StringBuffer result) {
+    if (fragmentBuffer.size() > 0) {
+      byte[] fragmentBytes = fragmentBuffer.toByteArray();
+      String fragment;
+      if (charset == null) {
+        fragment = new String(fragmentBytes);
+      } else {
+        try {
+          fragment = new String(fragmentBytes, charset);
+        } catch (UnsupportedEncodingException e) {
+          // Yikes, well try anyway:
+          fragment = new String(fragmentBytes);
+        }
+      }
+      fragmentBuffer.reset();
+      result.append(fragment);
+    }
+  }
+
   static String matchSingleVCardPrefixedField(String prefix, String rawText, boolean trim) {
     String[] values = matchVCardPrefixedField(prefix, rawText, trim);
     return values == null ? null : values[0];