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

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

Я хотел бы добиться этого с Greasemonkey и Firefox.

11 ответов

Решение

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


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

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

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".

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

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

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

Поэтому, если кто-то хочет версию образа для 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">

Эта функция берет 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")

Более современная версия ответа Кайидо с использованием fetch:

function toDataURL(url) {
  return fetch(url)
      .then((response)=> {
        return response.blob();
      })
      .then(blob=> {
        return URL.createObjectURL(blob);
      });
}

https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch

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

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

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

шайба / шайба / фиктивный

Если ваше изображение (а) уже загружено (или нет), этот "инструмент" может пригодиться:

Object.defineProperty
(
    HTMLImageElement.prototype,'toDataURL',
    {enumerable:false,configurable:false,writable:false,value:function(m,q)
    {
        let c=document.createElement('canvas');
        c.width=this.naturalWidth; c.height=this.naturalHeight;
        c.getContext('2d').drawImage(this,0,0); return c.toDataURL(m,q);
    }}
);

.. но почему?

Это дает преимущество использования "уже загруженных" данных изображения, поэтому дополнительный запрос не требуется. Кроме того, он позволяет конечному пользователю (программисту вроде вас) выбирать CORS и / илиmime-type а также quality-ИЛИ- вы можете не указывать эти аргументы / параметры, как описано в спецификации MDN здесь.

Если у вас загружен этот JS (до того, как он понадобится), преобразование в dataURL так же просто, как:

Примеры

HTML
<img src="/yo.jpg" onload="console.log(this.toDataURL('image/jpeg'))">
JS
console.log(document.getElementById("someImgID").toDataURL());

Снятие отпечатков с графического процессора

Если вас беспокоит "точность" битов, вы можете изменить этот инструмент в соответствии с вашими потребностями, как указано в ответе @Kaiido.

это 2022 год, я предпочитаю использовать современныеcreateImageBitmap()вместоonloadсобытие.

* примечание: изображение должно быть того же происхождения или с включенным CORS

Использовать 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>

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>
Вот пример работающей скрипки:- загрузить и получить данные изображения

Это все, что вам нужно прочитать.

https://developer.mozilla.org/en-US/docs/Web/API/FileReader/readAsBinaryString

var height = 200;
var width  = 200;

canvas.width  = width;
canvas.height = height;

var ctx = canvas.getContext('2d');

ctx.strokeStyle = '#090';
ctx.beginPath();
ctx.arc(width/2, height/2, width/2 - width/10, 0, Math.PI*2);
ctx.stroke();

canvas.toBlob(function (blob) {
  //consider blob is your file object

  var reader = new FileReader();

  reader.onload = function () {
    console.log(reader.result);
  }

  reader.readAsBinaryString(blob);
});

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

{
//...
canvas.width = img.naturalWidth; //img.width;
canvas.height = img.naturalHeight; //img.height;
//...
}
Другие вопросы по тегам