Кодирование и декодирование байта[] с помощью ZXing

я разрабатываю приложение для Android, и мне нужно кодировать и декодировать массив байтов в QRCode, сгенерированном с помощью приложения ZXing. Моя проблема в том, что мое декодированное сообщение точно не соответствует сгенерированному массиву байтов. Я попытался создать QRCode на основе массива байтов, содержащего инкрементные индексы, т. е.

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

и после кодирования сообщения в QRCode и декодирования его на стороне ответчика я получаю следующий вывод массива байтов:

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

все "отрицательные" значения байтов превращаются в ASCII char 63:'?- знаки вопроса. Я предполагаю, что что-то не так с кодировкой кодировки, но поскольку я использую ISO-8859-1, который каждый утверждает, что это решение такого рода проблемы (другая тема, рассматривающая тот же вопрос или здесь), Я не вижу, где моя ошибка, или если я пропускаю шаг за instanciation кодирования или декодирования. Вот код, который я выполняю для кодирования a заданный массив байтов:

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, я отправляю следующее намерение

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

}

не могли бы вы сказать мне, Где мои ошибки, или где я должен посмотреть?

Спасибо большое,

Франк

3 ответов


вы совершаете ошибку, думая, что вы можете превратить произвольные двоичные данные в допустимую строку без использования какой-либо брони. Это не работает. Binary - > text - > binary с потерями, используя любой из стандартных наборов символов / кодировки. (Подсказка: использование UTF-8 также не будет работать.)

вы должны использовать что-то вроде кодировки base64 или шестнадцатеричной кодировки, чтобы гарантировать, что двоичные данные не будут искажены.


в одном из моих приложений мне нужно было кодировать и декодировать массив байтов в QRCode, сгенерированном с помощью приложения ZXing. Поскольку массив байтов содержал сжатые текстовые данные, я хотел избежать кодировки base64. Это можно сделать, но поскольку я до сих пор не видел полного набора фрагментов кода, я опубликую их здесь.

кодировка:

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 в данных намерения для запуска сканирования-это точка, которая сделала код исходного вопроса неудачным. Мне потребовалось довольно много времени, чтобы выкопать это, поскольку я не видел этого четко нигде, и кодировка Latin 1 является стандартной кодировкой для QR-кода в Xzing. Особенно сложным является тот факт, что онлайн-декодер Xzing http://zxing.org/w/decode.jspx не устанавливает CHARACTER_SET, так что сгенерированный QR-код выглядит неисправным при декодировании на этом сайте.


концептуально QR-коды кодируют текст, а не байты. Внутри, конечно, они переводят ввод в серию байтов, хотя это непрозрачно для вызывающего абонента. Вы правы, что, как это происходит, выбор правильной кодировки позволит вам протащить байты, и ISO-8859-1 является правильным выбором здесь. Это действительно работает.

ASCII невозможно, так как он не определяет символы для >= 128, и UTF-8 определенно не будет работать

проблема здесь, вероятно, ваш код. Я не совсем понимаю, к чему вы клоните... похоже, вы настраиваетесь на отправку Intent где-то (для сканера штрих-кодов?) но тогда вы этого не делаете, вы просто делаете Intent и отправить его в какой-то код, скопированный из проекта? Я предполагаю, что что-то пошло не так с тем, как вы устанавливаете дополнительные услуги в Intent.

это должно быть намного проще, если вы делаете это в вашем приложении. Просто использовать QRCodeEncoder.encodeAsBitmap() непосредственно и удалите остальную часть этого.