Использование необработанных данных изображения из запроса ajax для URI данных
Я пытаюсь использовать комбинацию AJAX и URI данных для загрузки изображения JPEG и извлечения его EXIF-данных одним HTTP-запросом. Я изменяю библиотеку (https://github.com/kennydude/photosphere) для этого; в настоящее время эта библиотека использует два HTTP-запроса для установки источника изображения и получения данных EXIF.
Получение EXIF работает без проблем. Однако мне трудно использовать необработанные данные из запроса ajax в качестве источника для изображения.
Исходный код для небольшого теста техники:
<!DOCTYPE html>
<html>
<head>
<script type='text/javascript'>
function init()
{
// own ajax library - using it to request a test jpg image
new Ajax().sendRequest
(
"/images/photos/badger.jpg",
{ method : "GET",
callback: function(xmlHTTP)
{
var encoded = btoa (unescape(encodeURIComponent(xmlHTTP.responseText)));
var dataURL="data:image/jpeg;base64,"+encoded;
document.getElementById("image").src = dataURL;
}
}
);
}
</script>
<script type="text/javascript" src="http://www.free-map.org.uk/0.6/js/lib/Ajax.js"></script>
</head>
<body onload='init()'>
<img id="image" alt="data url loaded image" />
</body>
</html>
Я получаю то, что выглядит как чувствительные данные jpeg, отправленные обратно, а длина (в байтах) необработанных данных и исходных данных с базовым 64-кодированным, а затем незакодированным снова - одинаковые. Однако попытка установить изображение src не удалась как в Firefox (25), так и в Chrome (31) (текущие версии). - Chrome отображает значок "сломанное изображение", указывающий, что src является недопустимым.
Я использовал эту страницу mozilla для информации о кодировании/декодировании base64:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Base64_encoding_and_decoding
Любая идея, что может быть неправильным? Оглядываясь по сторонам, я могу создать сервер с кодировкой изображения с кодировкой base64, но можно ли это сделать на стороне клиента? Во-первых, на стороне сервера с кодировкой base64 явно увеличивается размер данных, и вся цель этого упражнения заключается в сокращении объема данных, передаваемых с сервера, а также количества запросов.
Спасибо,
Ник
Ответы
Ответ 1
Спасибо за это. Я немного поработал над этим, и оказалось, что есть решение по крайней мере в текущих версиях Firefox и Chrome (EDIT: IE10 тоже работает). Вы можете использовать XMLHttpRequest2 и использовать типизированный массив (Uint8Array). Работает следующий код:
<!DOCTYPE html>
<html>
<head>
<script type='text/javascript'>
function init()
{
var xmlHTTP = new XMLHttpRequest();
xmlHTTP.open('GET','/images/photos/badger.jpg',true);
// Must include this line - specifies the response type we want
xmlHTTP.responseType = 'arraybuffer';
xmlHTTP.onload = function(e)
{
var arr = new Uint8Array(this.response);
// Convert the int array to a binary string
// We have to use apply() as we are converting an *array*
// and String.fromCharCode() takes one or more single values, not
// an array.
var raw = String.fromCharCode.apply(null,arr);
// This works!!!
var b64=btoa(raw);
var dataURL="data:image/jpeg;base64,"+b64;
document.getElementById("image").src = dataURL;
};
xmlHTTP.send();
}
</script>
</head>
<body onload='init()'>
<img id="image" alt="data url loaded image" />
</body>
</html>
В основном вы запрашиваете двоичный ответ, а затем создаете 8-битный беззнаковый внутренний вид данных, прежде чем преобразовывать его обратно в (двоичную) строку String.fromCharCode(). Применить необходимо, поскольку String.fromCharCode() не принимает аргумент массива. Затем вы используете btoa(), создаете свой URL-адрес и затем работаете.
Для этого были полезны следующие ресурсы:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Typed_arrays?redirectlocale=en-US&redirectslug=JavaScript%2FTyped_arrays
и
http://www.html5rocks.com/en/tutorials/file/xhr2/
Ник
Ответ 2
Ответ Ник работает очень хорошо. Но когда я сделал это с довольно большим файлом, я получил переполнение стека на
var raw = String.fromCharCode.apply(null,arr);
Создание сырой строки в кусках хорошо работало для меня.
var raw = '';
var i,j,subArray,chunk = 5000;
for (i=0,j=arr.length; i<j; i+=chunk) {
subArray = arr.subarray(i,i+chunk);
raw += String.fromCharCode.apply(null, subArray);
}
Ответ 3
У меня возникли проблемы с описанным выше методом ArrayBuffer -> String -> Base64
, но он пробежал другой метод, используя Blob, который отлично поработал. Это не способ преобразования необработанных данных в Base 64 (как в заголовке), но это способ отображения необработанных данных изображения (как и в фактическом вопросе):
var xhr = new XMLHttpRequest();
xhr.responseType = 'arraybuffer';
xhr.onload = function() {
var blb = new Blob([xhr.response], {type: 'image/png'});
var url = (window.URL || window.webkitURL).createObjectURL(blb);
image.src = url;
}
xhr.open('GET', 'http://whatever.com/wherever');
xhr.send();
Весь кредит принадлежит Яну Миксовскому, автору этой скрипки. Я просто наткнулся на него и подумал, что это станет полезным дополнением к этой дискуссии.
Ответ 4
Вам нужно будет сделать кодировку base64 на стороне сервера, поскольку responseText обрабатывается как String, а данные ответа, отправляемые сервером, являются двоичными.