2012-06-16 15 views
7

Estoy desarrollando una aplicación de Android, y necesito codificar y decodificar una matriz de bytes en un QRCode generado con la aplicación ZXing. Mi problema es que mi mensaje decodificado no coincide exactamente con la matriz de bytes generada. I tratado de crear un QRCode basado en una matriz de bytes que contiene los índices de incremento, es decir,Byte de codificación y decodificación [] con ZXing

input = [0, 1, 2, ..., 124, 125, 126, 127, -128, -127,... -3, -2, -1, 0, 1, 2, ...] 

Y después de codificar el mensaje en el QRCode y decodificación en el lado respondedor, I obtener la siguiente salida de matriz de bytes:

output = [0, 1, 2, ..., 124, 125, 126, 127, 63, 63,... 63, 63, 63, 0, 1, 2, ...] 

Todos los valores de bytes "negativos" se convierten en ASCII char 63: '?' caracteres de interrogación. Supongo que algo va mal con el juego de caracteres de codificación, pero como estoy usando ISO-8859-1 que todos dicen ser la solución para ese tipo de problema (other topic treating the same kind of issue o here), no veo dónde está mi error , o si estoy omitiendo un paso durante la instanciación de la codificación o la decodificación. Aquí está el código que yo haga para codificar una matriz de bytes determinado:

String text = ""; 
byte[] res = new byte[272]; 
for (int i = 0; i < res.length; i++) { 
    res[i] = (byte) (i%256); 
} 
try { 
    text = new String(res, "ISO8859_1"); 
} catch (UnsupportedEncodingException e) { 
    // TODO 
} 
Intent intent = new Intent(Intents.Encode.ACTION); 
Intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET); 
intent.putExtra(Intents.Encode.TYPE, Contents.Type.TEXT); 
intent.putExtra(Intents.Encode.FORMAT, "ISO8859_1"); 
intent.putExtra(Intents.Encode.DATA, text); 
intent.putExtra(Intents.Encode.FORMAT, BarcodeFormat.QR_CODE.toString()); 

boolean useVCard = intent.getBooleanExtra(USE_VCARD_KEY, false); 
QRCodeEncoder qrCodeEncoder = new QRCodeEncoder(activity, intent, dimension, useVCard); 
Bitmap bitmap = qrCodeEncoder.encodeAsBitmap(); 

Y para decodificar un QR, le envío el siguiente Intención

@Override 
protected void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.qrcodeDecoding); 

    Intent intent = new Intent(Intents.Scan.ACTION); 
    intent.putExtra(Intents.Scan.MODE, Intents.Scan.QR_CODE_MODE); 
    startActivityForResult(intent, 0); 
} 

y esperar a que Resultado:

@Override 
protected void onActivityResult(int request, int result, Intent data) 
{ 
    if(request == 0) 
    { 
     //action 
     if(result == RESULT_OK) 
     { 
      String res = data.getStringExtra(Intents.Scan.RESULT); 
      byte[] dat = null; 

      try{ 
        dat = res.getBytes("ISO8859_1"); 
      } catch(UnsopportedEncodingException e) { 
        //TODO 
      } 
     } 
     else if(result == RESULT_CANCELED) 
     { 
      //TODO 
     } 
    } 

} 

¿Podría decirme dónde están mis errores o dónde debo mirarlos?

Gracias mucho,

Franck

+0

Solo para "jugar" (no tengo ni idea de esto) ¿qué sucede si usas UTF-8 como codificación, por ejemplo? – Ixx

+0

UTF-8 ciertamente no funcionará. No todas las secuencias de bytes son una secuencia UTF-8 válida para comenzar. Así que ni siquiera es posible obtener una cadena de la mayoría de las entradas de esa manera. –

Respuesta

2

Usted está haciendo el error de pensar que puede convertir los datos binarios arbitrarios en una cadena válida sin necesidad de utilizar algún tipo de blindaje. No funciona Binary -> text -> binary es con pérdida utilizando cualquiera de los conjuntos de caracteres estándar/codificación. (Sugerencia: el uso de UTF-8 tampoco funcionará).

Debe utilizar algo como codificación base64 o codificación hexadecimal para asegurarse de que los datos binarios no se dañen.

+1

Estoy de acuerdo con el sentimiento general; Sin embargo, ISO-8559-1 funciona para este propósito en Java. –

+0

@StephenC Muchas gracias, el uso de la codificación base64 en mi implementación resolvió el problema. – franckysnow

+1

@SeanOwen Estoy de acuerdo con usted, codificando y descodificando byte [] a la cadena ISO-8859-1 y viceversa. El problema puede estar ubicado en la capa ZXing. Sin embargo, base64 resolvió el caso. – franckysnow

1

Conceptualmente, los códigos QR codifican texto, no bytes. Por supuesto, traducen la entrada a una serie de bytes, aunque eso es opaco para la persona que llama. Tiene razón en que, como sucede, elegir la codificación correcta le permitirá pasar los bytes, y ISO-8859-1 es la elección correcta aquí. Funciona, en realidad.

ASCII no es posible, ya que no define caracteres para> = 128, y UTF-8 sin duda no va a trabajar

La cuestión aquí es probablemente su código. No estoy seguro de lo que está intentando aquí ... parece que está configurando para enviar un Intent a algún lugar (a Barcode Scanner?) Pero luego no lo hace, solo está haciendo un Intent y enviándolo a ¿Algún código que copiaste del proyecto? Imagino que algo ha ido mal con la forma en que está configurando extras en el Intent.

Esto debería ser mucho más simple si lo hace dentro de su aplicación. Simplemente reutilice QRCodeEncoder.encodeAsBitmap() directamente y elimine el resto de esto.

+0

El único constructor de 'QRCodeEncoder' toma los argumentos' QRCodeEncoder (Activity activity, Intent intent, int dimension, boolean useVCard) '. Y dado que no hay métodos setter, me dijo que era el único camino a seguir. Si pudieras ser un poco más específico sobre qué podría "salir mal" con los extras? Parece que la codificación base64 y la transmisión de una cadena ISO8859-1 al 'QRCodeEncoder' hicieron el truco. ¡Gracias! – franckysnow

+0

Quiero decir que no necesitas la clase para nada, solo copia el método que indiqué. El código en 'android /' no pretende ser una biblioteca; es nuestra aplicación El principal problema es que estás haciendo algo superfluo aquí: escuchar un "Intento" cuando no enviaste uno para contestar. Lea el javadoc para las teclas - 'FORMAT' no tiene nada que ver con la codificación de caracteres y lo configura dos veces. –

4

En una de mis aplicaciones necesité codificar y decodificar una matriz de bytes en un QRCode generado con la aplicación ZXing.Como la matriz de bytes contenía datos de texto comprimidos, quería evitar la codificación de base64. Es posible hacer esto, pero como hasta ahora no he visto un conjunto completo de fragmentos de código, los publicaré aquí.

Codificación:

public void showQRCode(Activity activity, byte[] data){ 
    Intent intent = new Intent("com.google.zxing.client.android.ENCODE"); 
    intent.putExtra("ENCODE_TYPE", "TEXT_TYPE"); 
    intent.putExtra("ENCODE_SHOW_CONTENTS", false); 
    intent.putExtra("ENCODE_DATA", new String(data, "ISO-8859-1")); 
    activity.startActivity(intent); 
} 

de escaneo de inicio:

public static void startQRCodeScan(Activity activity){ 
    Intent intent = new Intent(com.google.zxing.client.android.SCAN); 
    intent.putExtra("SCAN_MODE", "QR_CODE_MODE"); 
    intent.putExtra("CHARACTER_SET", "ISO-8859-1"); 
    activity.startActivityForResult(intent, 0); 
} 

escaneo de control de resultados:

public void onActivityResult(int requestCode, int resultCode, Intent intent) { 
    byte[] result = intent.getStringExtra("SCAN_RESULT").getBytes("ISO-8859-1"); 
    ... 
} 

creo que al no establecer CHARACTER_SET la norma ISO-8859-1 en los datos de intención de comenzar el escaneo es el punto que hizo que fallara el código de la pregunta original. Me tomó un buen tiempo desenterrar esto ya que no lo he visto claramente publicado en ninguna parte y la codificación Latin 1 es la codificación estándar para el código QR en Xzing. Especialmente complicado es el hecho de que el decodificador en línea Xzing http://zxing.org/w/decode.jspx no establece CHARACTER_SET también para que el código QR generado parezca defectuoso cuando se decodifica en este sitio.

Cuestiones relacionadas