it-swarm.com.de

Bilddaten in JavaScript abrufen?

Ich habe eine reguläre HTML-Seite mit einigen Bildern (nur normale <img /> HTML-Tags). Ich möchte ihren Inhalt vorzugsweise base64-codiert erhalten, ohne das Bild erneut herunterladen zu müssen (dh es wurde bereits vom Browser geladen, daher möchte ich jetzt den Inhalt).

Ich würde das gerne mit Greasemonkey und Firefox erreichen.

310
Detariael

Hinweis: Dies funktioniert nur, wenn das Image aus derselben Domäne stammt wie die Seite oder das Attribut crossOrigin="anonymous" besitzt und der Server CORS unterstützt. Sie erhalten auch nicht die Originaldatei, sondern eine neu codierte Version. Wenn Sie möchten, dass das Ergebnis mit dem Original identisch ist, siehe Kaiidos Antwort .


Sie müssen ein Leinwandelement mit den richtigen Abmessungen erstellen und die Bilddaten mit der Funktion drawImage kopieren. Dann können Sie die toDataURL-Funktion verwenden, um eine data: url abzurufen, die das Base-64-codierte Bild enthält. Beachten Sie, dass das Bild vollständig geladen sein muss. Andernfalls erhalten Sie ein leeres (schwarzes, transparentes) Bild.

Es wäre so etwas. Ich habe noch nie ein Greasemonkey-Skript geschrieben, daher müssen Sie möglicherweise den Code anpassen, um in dieser Umgebung ausgeführt zu werden.

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,/, "");
}

Ein JPEG-formatiertes Bild funktioniert bei älteren Firefox-Versionen (etwa 3.5) nicht. Wenn Sie dies unterstützen möchten, müssen Sie die Kompatibilität überprüfen. Wenn die Kodierung nicht unterstützt wird, wird standardmäßig "image/png" verwendet.

387
Matthew Crumley

Diese Funktion verwendet die URL und gibt dann das Bild BASE64 zurück

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;
}

Nenne es so: getBase64FromImageUrl("images/slbltxt.png")

73
MuniR

Kommen lange nach, aber keine der Antworten ist völlig richtig.

Wenn auf einer Leinwand gezeichnet, wird das übergebene Bild unkomprimiert + vorvervielfacht.
Wenn es exportiert wird, wird es mit einem anderen Algorithmus unkomprimiert oder rekomprimiert und nicht multipliziert.

Bei allen Browsern und Geräten treten bei diesem Vorgang unterschiedliche Rundungsfehler auf
(siehe Canvas Fingerprinting ).

Wenn Sie also eine base64-Version einer Image-Datei wünschen, müssen Sie sie erneut request (meistens wird sie aus dem Cache kommen), diesmal jedoch als Blob. 

Dann können Sie einen FileReader verwenden, um ihn entweder als ArrayBuffer oder als dataURL zu lesen.

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

40
Kaiido

Zusätzlich zu Matthews Antwort möchte ich sagen, dass image.width und image.height die angezeigte Größe des Bildes zurückgeben (und das Bild zuschneiden, wenn Sie es auf die Leinwand zeichnen).

Verwenden Sie stattdessen naturalWidth und naturalHeight, wobei das Bild in Originalgröße verwendet wird.

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

22
cube45

Eine modernere Version der Antwort von kaiido mit fetch wäre:

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

11
Zaptree

Verwenden Sie das Ereignis onload, um das Bild nach dem Laden zu konvertieren

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>
1

Verwenden Sie in HTML5 besser dies:

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