JavaScriptで画像データのURLを取得しますか?


335

いくつかの画像(通常の<img />HTMLタグのみ)を含む通常のHTMLページがあります。画像を再ダウンロードする必要なく、base64でエンコードされたコンテンツを取得したいと考えています(つまり、ブラウザーによって既にロードされているため、コンテンツが必要です)。

GreasemonkeyとFirefoxでそれを実現したいです。

回答:


400

注:これは、画像がページと同じドメインからのものであるか、crossOrigin="anonymous"属性があり、サーバーがCORSをサポートしている場合にのみ機能します。また、元のファイルではなく、再エンコードされたバージョンが提供されます。結果を元と同じにする必要がある場合は、海道の回答を参照してください。


正しい寸法のキャンバス要素を作成し、drawImage関数を使用して画像データをコピーする必要があります。次に、toDataURL関数を使用して、base-64でエンコードされた画像を含むdata:urlを取得できます。画像は完全に読み込まれている必要があります。そうしないと、空の(黒の透明な)画像が返されます。

こんな感じになります。私は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形式の画像の取得は、Firefoxの古いバージョン(約3.5)では機能しないため、サポートする場合は、互換性を確認する必要があります。エンコードがサポートされていない場合、デフォルトで「image / png」になります。


1
これは機能しているようですが(エスケープされていない/戻り値を除く)、file_get_contents関数で取得したファイルでbase64_encodeを実行したときにPHPから取得したものと同じbase64文字列は作成されません。画像は非常に似ている/同じように見えますが、それでもJavaScriptの画像は小さく、まったく同じであることが好きです。もう1つ:入力画像が小さく(594バイト)、背景が透明な28x30のPNG-何かが変わった場合。
Detariael 09年

7
Firefoxは、エンコーディングに影響する別の圧縮レベルを使用している可能性があります。また、PNGはノートのような追加のヘッダー情報をサポートしていると思います。キャンバスはピクセルデータしか取得しないため、失われます。完全に同じにする必要がある場合は、おそらくAJAXを使用してファイルを取得し、base64で手動でエンコードできます。
Matthew Crumley、

7
はい、XMLHttpRequestで画像をダウンロードします。うまくいけば、画像のキャッシュされたバージョンを使用しますが、それはサーバーとブラウザの構成に依存し、ファイルが変更されたかどうかを判断するためのリクエストオーバーヘッドが発生します。だから私はそもそもそれを提案しませんでした:-)残念ながら、私が知る限り、それが元のファイルを取得する唯一の方法です。
Matthew Crumley、

2
@trusktr drawImageは何も実行せず、空白のキャンバスと結果の画像が作成されます。
Matthew Crumley、2012年

1
@JohnSewellこれは、OPがURLではなくコンテンツを必要としているためです。画像ソースとして使用する場合は、replace(...)呼び出しをスキップする必要があります。
Matthew Crumley、2016年

76

この関数は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")


8
画像を外部リンクからbase 64に変換する方法はありますか?
dinodsaurus、2013年

@dinodsaurusを画像タグにロードしたり、ajaxクエリを実行したりできます。
Jared Forsyth

6
CORSを実装する必要がありますが、$。ajax(theimageurl)を実行するだけで、妥当なものを返すはずです。それ以外の場合(CORSが有効になっていない場合)は機能しません。インターネットのセキュリティモデルはそれを許可しません。もちろん、あなたがChromeプラグインの内部にいる場合を除いて、その場合はすべて許可されます-上記の例でさえ
Jared Forsyth

4
Operaなどの一部のブラウザーではイベントが発生しないため、のimg.src =img.onload =に配置する必要があります。
ostapische

1
@Hakkarメモリリークは、まだ参照カウントを使用してガベージコレクションに通知する古いブラウザでのみ発生します。私の理解では、循環参照はマークとスイープのセットアップでリークを作成しません。機能スコープたらgetBase64FromImageUrl(url)とがimg.onload = function ()終了しているIMGが到達不能であるとごみを収集します。IE 6/7以外は問題ありません。
humanityANDpeace

59

長い間出てきますが、ここでの答えはどれも完全に正しいものではありません。

キャンバスに描画されるとき、渡された画像は圧縮されていない+すべて事前に乗算されています。
エクスポートされると、非圧縮または別のアルゴリズムで再圧縮され、乗算されません。

すべてのブラウザーとデバイスで、このプロセスで発生する異なる丸めエラーが発生します
Canvasフィンガープリントを参照)。)。

したがって、画像ファイルの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">


5つ以上の異なる質問を通過しただけで、コードは正しく機能する唯一の質問です。おかげで:)
Peter

1
上記のコードでこのエラーが発生します。 XMLHttpRequest cannot load data:image/jpeg;base64,/9j/4AA ... /2Q==. Invalid response. Origin 'https://example.com' is therefore not allowed access.
STウィルソン2017年

2
@STWilson、はい、このメソッドも、キャンバスと同じように、同じ生成元のポリシーに関連付けられています。クロスオリジンリクエストの場合は、そのようなクロスオリジンリクエストをスクリプトに許可するようにホスティングサーバーを設定する必要があります。
海洋堂

@Kaiidoでは、画像がスクリプト以外のサーバーにある場合、ホスティングサーバーはクロスオリジンリクエストを有効にする必要がありますか?img.setAttribute( 'crossOrigin'、 'anonymous')を設定すると、エラーが回避されますか?
1.21ギガワット

1
さらに調査すると、画像はcrossOrigin属性を使用してアクセスをリクエストできるように見えますが、CORSヘッダーsitepoint.com/an-in-depth-look-at-corsを介してアクセスを提供するのはホスティングサーバー次第です。XMLHttpRequestについては、サーバーはCORSヘッダーを介して画像と同じアクセス権を付与する必要があるようですが、xhr.withCredentialsをfalse(デフォルト)に設定することを除いて、コードを変更する必要はありません。
1.21ギガワット

20

フェッチを使用した、より新しいバージョンのkaiidoの回答は次のようになります。

function toObjectUrl(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

編集:コメントで指摘されているように、これは実際のDataURLではなくローカルシステム内のファイルを指すオブジェクトURLを返すため、ユースケースによってはこれが必要なものではない場合があります。

あなたはフェッチと実際のdataURLを使用するために次の答えを見ることができます:https ://stackoverflow.com/a/50463054/599602


2
URL.revokeObjectURL()このメソッドを使用してアプリケーションを長時間実行している場合は、忘れずに呼び出してください。そうしないと、メモリが乱雑になります。
エンジニア

1
注意:DataURL(base64エンコード)はObjectURL(Blobへの参照)と同じではありません
DaniEll

1
ObjectURLは確かにデータURLではありません。これは正解ではありません。
ダニー・林

2

シブ/シム/シャム

画像が既にロードされている(またはロードされていない)場合は、この「ツール」が便利です。

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、-OR-を使用したりして、qualityこれらの引数/パラメーターをここMDN仕様説明されているように省略することができます。

このJSがロードされている場合(必要なときより前)、変換dataURLは次のように簡単です。

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

GPUフィンガープリント

ビットの「正確さ」が気になる場合は、@ Kaiidoの回答で示されているように、このツールをニーズに合わせて変更できます。


1

使用するonloadロード後に変換イメージにイベントを


-3

HTML5では、これをより適切に使用します。

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

2
質問に答えるときは、より具体的で詳細な説明を提供してください。
Piyush Zalani
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.