Загрузка и преобразование изображения в URI данных в QML - PullRequest
0 голосов
/ 21 декабря 2018

Я работаю над приложением, созданным с использованием QML, Qt 5.11.2 и платформы ESRI ArcGIS AppStudio 3.2.Мне нужно загрузить некоторые изображения в формате JPEG для просмотра в автономном режиме, а затем иметь возможность отображать их в элементе изображения, если пользователь впоследствии выберет соответствующую запись.Мой предпочтительный подход заключается в том, чтобы вызвать XMLHttpRequest в JavaScript, преобразовать ответ в URI данных, сохранить его в нашей базе данных SQLite, а затем просто при необходимости назначить URI данных источнику Image.Каждый шаг этого процесса работает, за исключением преобразования ответа XMLHttpRequest в URI данных.У меня есть следующий код JS, который работает в браузере:

var url = 'https://firebasestorage.googleapis.com/v0/b/christophereby-3733b.appspot.com/o/icon1.png?alt=media';
var xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
xhr.onreadystatechange = function() {
  if (xhr.readyState === XMLHttpRequest.DONE) {
    if (xhr.status === 200) {
      var response = xhr.responseText;
      var binary = "";
      for (var i = 0; i < response.length; i++) {
        binary += String.fromCharCode(response.charCodeAt(i) & 0xff);
      }
      var image = 'data:image/jpeg;base64,' + btoa(binary);
      document.getElementById('img').src = image;
    }
  }
}
xhr.overrideMimeType('text/plain; charset=x-user-defined');
xhr.send();
<img src="#" id="img" />

Однако реализация XMLHttpRequest в Qt не поддерживает метод overrideMimeType, и кажется, что ответ по-разному кодируется междубраузер и реализация Qt.Например, метод response.charCodeAt (i) возвращает 63369 для первого символа в браузере и 65533 в Qt.Другие методы JS (установка XHR responseType, использование объекта Blob и т. Д.) Не поддерживаются в Qt 5.11.

Вот пример кода в QML, который не работает:

import QtQuick 2.7
import ArcGIS.AppFramework 1.0

App {
    id: app
    width: 400
    height: 640

    Component.onCompleted: {
        var url = 'https://firebasestorage.googleapis.com/v0/b/christophereby-3733b.appspot.com/o/icon1.png?alt=media';
        var xhr = new XMLHttpRequest();
        xhr.open('GET', url, true);
        xhr.onreadystatechange = function() {
          if (xhr.readyState === XMLHttpRequest.DONE) {
            if (xhr.status === 200) {
              var response = xhr.responseText;
              var binary = "";
              for (var i = 0; i < response.length; i++) {
                binary += String.fromCharCode(response.charCodeAt(i) & 0xff);
              }
              var image = 'data:image/jpeg;base64,' + Qt.btoa(binary);
              img.source = image;
            }
          }
        }
        xhr.send();
    }
    Image {
        id: img
    }
}

Я также пытался использовать объект QML ArcGIS.AppFramework NetworkRequest для загрузки изображения.Я могу получить это, чтобы сохранить изображение в файловой системе, используя следующий код:

NetworkRequest {
    url: 'https://firebasestorage.googleapis.com/v0/b/christophereby-3733b.appspot.com/o/icon1.png?alt=media'
    responsePath: "~/ArcGIS/%1".arg('test.jpeg')
    responseType: "blob"
    onReadyStateChanged: {
         if(readyState === NetworkRequest.DONE) {
              console.log(response); //This is undefined
         }
    }
}

Однако я хочу сделать это в памяти и, используя этот подход, я не могу получить доступ к объекту ответа из onReadyStateChangedметод, когда я устанавливаю responseType для blob.Установка responseType для текста приводит к тем же проблемам, которые у меня были с запросом XHR.

Я нашел этот SO-ответ , но альтернативы варианту 3, которые я пробовал выше, включают в себя написание кода C ++, который я не хочу делать для обеспечения максимальной совместимости с ArcGIS AppStudio.Есть ли что-то, что я делаю неправильно в моем коде выше, или есть другой подход, который я могу использовать?

1 Ответ

0 голосов
/ 28 декабря 2018

Отчет об ошибке Qt для метода XMLHttpRequest overrideMimeType, который не был реализован (ссылки на комментарии eyllanesc, на которые мне указали), указывает на некоторую поддержку буферов массива.Основываясь на этом и глядя на исходный код QQmlXMLHttpRequest, я смог заставить это работать.Вот пример (у меня был собственный кодировщик Base64, так как Qt.btoa не работал):

import QtQuick 2.7
import ArcGIS.AppFramework 1.0

App {
    id: app
    width: 400
    height: 640

    Component.onCompleted: {
        var url = 'https://firebasestorage.googleapis.com/v0/b/christophereby-3733b.appspot.com/o/icon1.png?alt=media';
        var xhr = new XMLHttpRequest();
        xhr.open('GET', url, true);
        xhr.responseType = 'arraybuffer';
        xhr.onreadystatechange = function() {
            if (xhr.readyState === XMLHttpRequest.DONE) {
                if (xhr.status === 200) {
                    var response = new Uint8Array(xhr.response);
                    var raw = "";
                    for (var i = 0; i < response.byteLength; i++) {
                        raw += String.fromCharCode(response[i]);
                    }

                    //FROM https://cdnjs.cloudflare.com/ajax/libs/Base64/1.0.1/base64.js
                    function base64Encode (input) {
                        var chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
                        var str = String(input);
                        for (
                            // initialize result and counter
                            var block, charCode, idx = 0, map = chars, output = '';
                            str.charAt(idx | 0) || (map = '=', idx % 1);
                            output += map.charAt(63 & block >> 8 - idx % 1 * 8)
                            ) {
                            charCode = str.charCodeAt(idx += 3/4);
                            if (charCode > 0xFF) {
                                throw new Error("Base64 encoding failed: The string to be encoded contains characters outside of the Latin1 range.");
                            }
                            block = block << 8 | charCode;
                        }
                        return output;
                    }
                    var image = 'data:image/png;base64,' + base64Encode(raw);
                    img.source = image;
                }
            }
        }
        xhr.send();
    }
    Image {
        id: img
    }
}
...