Сохранение изображения холста с помощью JavaScript из Safari (5.0.x) в AppEngine Blobstore - PullRequest
4 голосов
/ 04 июля 2011

Моя команда и я недовольны тем, что наше удивительное анимационное приложение не работает в Safari из-за сочетания ограничений Safari и AppEngine. Мы надеемся, что один из вас поможет нам найти «магическое заклинание», чтобы решить его.

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

Позвольте мне объяснить детали проблемы.

Наше приложение должно сохранять данные холста в blobstore (изображения, которые пользователь нарисовал для своей анимации.) Обычно это можно сделать, разместив веб-форму динамически через ajax, в котором есть двоичное поле с данными изображения. Один из способов сделать это - использовать ArrayBuffer и BlobBuilder. Это работает с Chrome:

dataURItoBlob = function(dataURI, callback) {
  var ab, bb, byteString, i, ia, mimeString, _ref;
  if (!(typeof ArrayBuffer != "undefined" && ArrayBuffer !== null)) {
    return null;
  }
  byteString = atob(dataURI.split(',')[1]);
  mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0];
  ab = new ArrayBuffer(byteString.length);
  ia = new Uint8Array(ab);
  for (i = 0, _ref = byteString.length; (0 <= _ref ? i < _ref : i > _ref); (0 <= _ref ? i += 1 : i -= 1)) {
    ia[i] = byteString.charCodeAt(i);
  }
  bb = window.BlobBuilder ? new BlobBuilder() : window.WebKitBlobBuilder ? new WebKitBlobBuilder() : window.MozBlobBuilder ? new MozBlobBuilder() : void 0;
  if (bb != null) {
    bb.append(ab);
    return bb.getBlob(mimeString);
  } else {
    return null;
  }
};
postCanvasToBlobstore = function(url, name, canvas) {
        blob = dataURItoBlob(canvas.toDataURL());
        formData = new FormData();
        formData.append("file", blob);
        xhr = new XMLHttpRequest();
        xhr.open("POST", url);
        return xhr.send(formData);
}

Другой способ сохранить данные в двоичной форме - использовать xhr.sendAsBinary (). Это работает для Firefox:

postCanvasToBlobstore = function(url, name, canvas) {
  type='image/png'
  var arr, boundary, data, j, xhr;
  data = canvas.toDataURL(type);
  data = data.replace('data:' + type + ';base64,', '');
  xhr = new XMLHttpRequest();
  xhr.open('POST', url, true);
  boundary = 'imaboundary';
  xhr.setRequestHeader('Content-Type', 'multipart/form-data; boundary=' + boundary);
    arr = ['--' + boundary, 'Content-Disposition: form-data; name="' + name + '"; filename="' + name + '"', 'Content-Type: ' + type, '', atob(data), '--' + boundary + '--'];
  j = arr.join('\r\n');
  return xhr.sendAsBinary(j);
}

Кажется, что ни одна из этих возможностей не существует для Safari (хотя это очень возможно, но мы не достаточно умны, чтобы понять это). Одна альтернатива - просто использовать данные, закодированные в base64, что Safari может сделать наверняка. Вот как это будет выглядеть:

postCanvasToBlobstore = function(url, name, canvas, type) {
  type='image/png'
  var arr, boundary, data, j, xhr;
  data = canvas.toDataURL(type);
  data = data.replace('data:' + type + ';base64,', '');
  xhr = new XMLHttpRequest();
  xhr.open('POST', url, true);
  boundary = 'imaboundary';
  xhr.setRequestHeader('Content-Type', 'multipart/form-data; boundary=' + boundary);
    arr = ['--' + boundary, 'Content-Disposition: form-data; name="' + name + '"; filename="' + name + '"', 'Content-Transfer-Encoding: base64','Content-Type: ' + type, '', data, '--' + boundary + '--'];
  j = arr.join('\r\n');
  return xhr.send(j);
}

Теперь это действительно работает! Однако он работает только с версией разработки инструментов AppEngine из-за известной ошибки в хранилище больших двоичных объектов: в тот момент, когда вы запускаете приложение в производство, оно перестает работать. Конечно, возможно, что где-то настройка кода POST может решить проблему, с которой сталкивается blobstore при интерпретации данных. См. http://code.google.com/p/googleappengine/issues/detail?id=4265 о том, что, по-видимому, является проблемой хранилища, связанной с этой проблемой.

Вы можете вставить любой из трех приведенных выше примеров кода в элемент управления редактирования и посмотреть, что происходит с каждой версией функции postCanvasToBlobstore: первый пример будет работать в Chrome, второй - в Firefox (и является версией отладочное приложение по умолчанию), и третий должен работать из всех трех (но не работает ни для одного из них при использовании этого производственного веб-сайта, вероятно, из-за ошибки в магазине.)

Ответы [ 2 ]

3 голосов
/ 04 июля 2011

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

К счастью, мы недавно выпустили Файловый API , который позволяет программно выполнять запись в blobstore, а также мы увеличили ограничение на количество запросов на загрузку до 32 МБ. Пока ваши полезные данные меньше этого размера, вы можете написать обработчик, который будет принимать загрузку в любом удобном для вас формате, и сохранять его в хранилище блогов самостоятельно. Я бы порекомендовал сохранить механизм регулярной загрузки, поскольку он более эффективен, когда его практично использовать, но это зависит от вас.

Имейте в виду, что отдельные вызовы API-интерфейсов App Engine по-прежнему имеют ограничение по размеру; чтобы записать весь файл, вам нужно сделать несколько звонков на write. Для получения дополнительной информации см. Мой ответ на этот связанный вопрос .

1 голос
/ 04 июля 2011

То, что я делаю, это Shard / Chunk base64 от canvas до rpc, около 25000 char через rpc, затем я разбив его до 900 символов и сохраню их в таблицу tmp в хранилище данных как TEXT. Как только это сделано, я делаю несколько проверок, чтобы убедиться, что все там. Затем я декодирую его в буфере.

Вот некоторые из источников: GAEDatastore

Есть еще вопросы: branflake2267

Пожалуйста, отметьте этот выпуск.

Прокомментируйте, пожалуйста, на форуме App Engine , чтобы инженеры тоже это видели:

Надеюсь, это поможет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...