【问题标题】:Encoding and decoding byte[] with ZXing用 ZXing 编码和解码 byte[]
【发布时间】:2012-06-19 12:43:15
【问题描述】:

我正在开发一个 Android 应用程序,我需要在使用 ZXing 应用程序生成的 QRCode 中对字节数组进行编码和解码。我的问题是我解码的消息与生成的字节数组不完全匹配。 我试图创建一个基于包含递增索引的字节数组的二维码,即

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

在二维码中对消息进行编码并在响应端解码后,我得到以下字节数组输出:

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

所有“负”字节值都转换为 ASCII 字符 63:'?'问号字符。 我认为编码字符集出了点问题,但由于我使用的是 ISO-8859-1,每个人都声称这是此类问题的解决方案(other topic treating the same kind of issuehere),我看不出在哪里是我的错误,或者如果我在编码或解码的实例化过程中跳过了一个步骤。 这是我为给定字节数组编码而执行的代码:

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();

为了解码 QRCode,我发送以下 Intent

@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);
}

然后等待结果:

@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
        }
    }

}

你能告诉我我的错误在哪里,或者我应该看看哪里?

非常感谢,

弗兰克

【问题讨论】:

  • 只是为了“玩”(我对此一无所知)如果您使用 UTF-8 作为编码会发生什么?
  • UTF-8 肯定行不通。首先,并非每个字节序列都是有效的 UTF-8 序列。因此,甚至不可能以这种方式从大多数输入中获取字符串。

标签: java android character-encoding zxing iso-8859-1


【解决方案1】:

在我的一个应用程序中,我需要对使用 ZXing 应用程序生成的 QRCode 中的字节数组进行编码和解码。由于字节数组包含压缩文本数据,我想避免使用 base64 编码。可以这样做,但由于我到目前为止还没有看到完整的代码 sn-ps 集,所以我将它们发布在这里。

编码:

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);
}

开始扫描:

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);
}

扫描结果处理程序:

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

我认为在开始扫描的意图数据中未将 CHARACTER_SET 设置为 ISO-8859-1 是导致原始问题代码失败的原因。我花了很长时间才弄清楚这个问题,因为我在任何地方都没有看到这个清晰的帖子,而且拉丁 1 编码是 Xzing 中 QR 码的标准编码。特别棘手的是,Xzing 在线解码器http://zxing.org/w/decode.jspx 也没有设置 CHARACTER_SET,因此生成的 QR 码在此站点上解码时看起来有问题。

【讨论】:

    【解决方案2】:

    您错误地认为可以将任意二进制数据转换为有效字符串,而无需使用某种装甲。它不起作用。 Binary -> text -> binary 使用任何标准字符集/编码都是有损的。 (提示:使用 UTF-8 也不行。)

    您应该使用 base64 编码或十六进制编码来确保二进制数据不会被破坏。

    【讨论】:

    • 我同意整体观点;不过,ISO-8559-1 在 Java 中确实适用于此目的。
    • @StephenC 非常感谢,在我的实现中使用base64编码解决了这个问题!
    • @SeanOwen 我同意你的看法,将 byte[] 编码和解码为 String ISO-8859-1,反之亦然。问题可能出在ZXing层。然而,base64 解决了这个问题。
    • 我的理解是 ISO-8859-1 在将任意缓冲区转换为字符串时是 100% 有效的。 base64 为 75%。我的理解错了吗?
    • @LucaCarlon - 不,不是。但效率并不是唯一的问题。
    【解决方案3】:

    从概念上讲,二维码编码的是文本,而不是字节。当然,它们在内部将输入转换为一系列字节,尽管这对调用者来说是不透明的。你是对的,碰巧选择正确的编码会让你偷偷通过,而 ISO-8859-1 是正确的选择。它确实有效。

    ASCII 是不可能的,因为它没有为 >= 128 定义字符,而且 UTF-8 肯定行不通

    这里的问题可能是您的代码。我不确定你在这里尝试什么......看起来你正在设置在某处发送Intent(到条形码扫描仪?)但你没有,你只是在制作Intent并将其发送到您从项目中复制的一些代码?我想您在 Intent 上设置附加内容的方式出了点问题。

    如果您在应用程序中执行此操作,这应该会简单得多。只需直接重用QRCodeEncoder.encodeAsBitmap() 并删除其余部分即可。

    【讨论】:

    • QRCodeEncoder 的唯一构造函数接受参数QRCodeEncoder(Activity activity, Intent intent, int dimension, boolean useVCard)。而且由于没有 setter 方法,我认为这是唯一的方法。如果您可以更具体地说明附加功能可能会“出错”吗?似乎 base64 编码并将 ISO8859-1 字符串传递给QRCodeEncoder 是成功的。谢谢!
    • 我的意思是你根本不需要这个类——只需复制我指出的方法。 android/ 中的代码不是作为库;这是我们的应用程序。主要问题是您在这里做了一些多余的事情——当您没有发送回复时,您正在收听Intent。阅读键的 javadoc -- FORMAT 与字符编码无关,您设置了两次。
    猜你喜欢
    • 1970-01-01
    • 2011-01-30
    • 2017-12-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多