Получить URL-адрес данных изображения в JavaScript?

У меня есть обычная HTML-страница с некоторыми изображениями (только регулярные теги <img /> HTML). Я хотел бы получить их контент, предварительно закодированный base64, без необходимости повторной загрузки изображения (т.е. Он уже загружен браузером, поэтому теперь я хочу контент).

Мне бы хотелось достичь этого с помощью Greasemonkey и Firefox.

Ответ 1

Примечание.. Это работает только в том случае, если изображение находится в том же домене, что и страница, или имеет атрибут crossOrigin="anonymous", а сервер поддерживает CORS. Это также не даст вам оригинальный файл, а перекодированную версию. Если вам нужно, чтобы результат был идентичен оригиналу, см. ответ Кайдо.


Вам нужно будет создать элемент холста с правильными размерами и скопировать данные изображения с помощью функции drawImage. Затем вы можете использовать функцию toDataURL для получения данных: url с кодировкой base-64. Обратите внимание, что изображение должно быть полностью загружено или вы просто получите пустое (черное, прозрачное) изображение.

Это было бы так. Я никогда не писал Greasemonkey script, поэтому вам может потребоваться настроить код для работы в этой среде.

function getBase64Image(img) {
    // Create an empty canvas element
    var canvas = document.createElement("canvas");
    canvas.width = img.width;
    canvas.height = img.height;

    // Copy the image contents to the canvas
    var ctx = canvas.getContext("2d");
    ctx.drawImage(img, 0, 0);

    // Get the data-URL formatted image
    // Firefox supports PNG and JPEG. You could check img.src to
    // guess the original format, but be aware the using "image/jpg"
    // will re-encode the image.
    var dataURL = canvas.toDataURL("image/png");

    return dataURL.replace(/^data:image\/(png|jpg);base64,/, "");
}

Получение изображения в формате JPEG не работает в более ранних версиях (около 3,5) Firefox, поэтому, если вы хотите его поддерживать, вам необходимо проверить совместимость. Если кодировка не поддерживается, по умолчанию будет отображаться "image/png".

Ответ 2

Эта функция принимает URL-адрес и возвращает изображение BASE64

function getBase64FromImageUrl(url) {
    var img = new Image();

    img.setAttribute('crossOrigin', 'anonymous');

    img.onload = function () {
        var canvas = document.createElement("canvas");
        canvas.width =this.width;
        canvas.height =this.height;

        var ctx = canvas.getContext("2d");
        ctx.drawImage(this, 0, 0);

        var dataURL = canvas.toDataURL("image/png");

        alert(dataURL.replace(/^data:image\/(png|jpg);base64,/, ""));
    };

    img.src = url;
}

Назовите его так: getBase64FromImageUrl("images/slbltxt.png")

Ответ 3

Приходится долго, но ни один из ответов здесь не является полностью правильным.

При рисовании на холсте переданное изображение несжатое + все предварительно умноженное.
При экспорте он несжатый или повторно сжатый с другим алгоритмом и не умноженный.

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

Поэтому, если вам нужна версия файла образа base64, они должны запросить ее снова (большую часть времени она будет поступать из кеша), но на этот раз как Blob.

Затем вы можете использовать FileReader для чтения либо как ArrayBuffer, либо как dataURL.

function toDataURL(url, callback){
    var xhr = new XMLHttpRequest();
    xhr.open('get', url);
    xhr.responseType = 'blob';
    xhr.onload = function(){
      var fr = new FileReader();
    
      fr.onload = function(){
        callback(this.result);
      };
    
      fr.readAsDataURL(xhr.response); // async call
    };
    
    xhr.send();
}

toDataURL(myImage.src, function(dataURL){
  result.src = dataURL;

  // now just to show that passing to a canvas doesn't hold the same results
  var canvas = document.createElement('canvas');
  canvas.width = myImage.naturalWidth;
  canvas.height = myImage.naturalHeight;
  canvas.getContext('2d').drawImage(myImage, 0,0);

  console.log(canvas.toDataURL() === dataURL); // false - not same data
  });
<img id="myImage" src="https://dl.dropboxusercontent.com/s/4e90e48s5vtmfbd/aaa.png" crossOrigin="anonymous">
<img id="result">

Ответ 4

В дополнение к ответу matthew, я хотел бы сказать, что image.width и image.height возвращают отображаемый размер изображения (и обрезают изображение при рисовании его на холст)

Вместо этого используйте naturalWidth и naturalHeight, который использует изображение в реальном размере.

См. http://www.whatwg.org/specs/web-apps/current-work/multipage/edits.html#dom-img-naturalwidth

Ответ 6

Используйте событие onload для преобразования изображения после загрузки

function loaded(img) {
  let c = document.createElement('canvas')
  c.getContext('2d').drawImage(img, 0, 0)
  msg.innerText= c.toDataURL();
}
pre { word-wrap: break-word; width: 500px; white-space: pre-wrap; }
<img onload="loaded(this)" src="https://cors-anywhere.herokuapp.com/http://lorempixel.com/200/140" crossorigin="anonymous"/>

<pre id="msg"></pre>

Ответ 7

function encodeImageFileAsURL(cb) {
    return function() {
        var file = this.files[0];
        var reader = new FileReader();
        reader.onloadend = function() {
            cb(reader.result);
        }
        reader.readAsDataURL(file);
    }
}

$('#inputFileToLoad').change(encodeImageFileAsURL(function(base64Img) {
    $('.output')
        .find('textarea')
        .val(base64Img)
        .end()
        .find('a')
        .attr('href', base64Img)
        .text(base64Img)
        .end()
        .find('img')
        .attr('src', base64Img);
}));
@import url('//netdna.bootstrapcdn.com/bootstrap/3.1.0/css/bootstrap.min.css'); body{ padding: 20px; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<h2>Input</h2>
<form class="input-group" id="img2b64">
    <input id="inputFileToLoad" type="file" onchange="encodeImageFileAsURL();" />
</form>
<hr>

Ответ 8

В HTML5 лучше использовать это:

{
//...
canvas.width = img.naturalWidth; //img.width;
canvas.height = img.naturalHeight; //img.height;
//...
}