JavaScript'te resim verileri URL'si mi aldınız?


335

Bazı resimlerle düzenli bir HTML sayfam var (sadece normal <img />HTML etiketleri). Görüntüsünü yeniden indirmeye gerek kalmadan, içeriklerini base64 kodlu olarak almak istiyorum (yani tarayıcı tarafından zaten yüklenmiş, bu yüzden şimdi içeriği istiyorum).

Bunu Greasemonkey ve Firefox ile başarmayı çok isterim.

Yanıtlar:


400

Not: Bu yalnızca resim sayfa ile aynı alan adından geliyorsa veya crossOrigin="anonymous"özniteliğe sahipse ve sunucu CORS'yi destekliyorsa çalışır. Ayrıca orijinal dosyayı değil, yeniden kodlanmış bir sürümü verecektir. Sonucun orijinaliyle aynı olması gerekiyorsa, Kaiido'nun cevabına bakın .


Doğru boyutlara sahip bir tuval öğesi oluşturmanız ve görüntü verilerini drawImageişlevle kopyalamanız gerekir . Sonra toDataURLişlevi bir veri almak için kullanabilirsiniz : base-64 kodlu görüntüye sahip url. Resmin tam olarak yüklenmesi gerektiğini veya yalnızca boş (siyah, şeffaf) bir resim elde edeceğinizi unutmayın.

Böyle bir şey olurdu. Asla bir Greasemonkey betiği yazmadım, bu yüzden bu ortamda çalıştırmak için kodu ayarlamanız gerekebilir.

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 biçimli bir görüntü elde etmek Firefox'un eski sürümlerinde (yaklaşık 3.5) çalışmaz, bu nedenle bunu desteklemek istiyorsanız uyumluluğu kontrol etmeniz gerekir. Kodlama desteklenmiyorsa, varsayılan olarak "image / png" olarak ayarlanır.


1
Bu çalışıyor gibi görünüyor olsa da (unescaped / dönüşte hariç), file_get_contents işleviyle elde edilen dosyada base64_encode yaparken PHP'den aldığım base64 dizesini oluşturmaz. Görüntüler çok benzer / aynı görünüyor, yine de Javascripted olan daha küçük ve tam olarak aynı olmalarını isterdim. Bir şey daha var: giriş görüntüsü, şeffaf bir arka plana sahip küçük bir (594 bayt), 28x30 PNG'dir - bu bir şey değiştirirse.
Detariael

7
Firefox, kodlamayı etkileyecek farklı bir sıkıştırma seviyesi kullanıyor olabilir. Ayrıca, bence PNG, tuval yalnızca piksel verilerini aldığından, notlar gibi bazı ekstra başlık bilgilerini destekliyor. Tam olarak aynı olması gerekiyorsa, muhtemelen dosyayı almak ve AJ64'ü manuel olarak kodlamak için AJAX kullanabilirsiniz.
Matthew Crumley

7
Evet, resmi XMLHttpRequest ile indirirsiniz. Umarım, görüntünün önbelleğe alınmış sürümünü kullanır, ancak bu sunucu ve tarayıcı yapılandırmasına bağlıdır ve dosyanın değişip değişmediğini belirlemek için ek yükü istersiniz. Bu yüzden ilk etapta önermedim :-) Ne yazık ki, bildiğim kadarıyla, orijinal dosyayı almanın tek yolu bu.
Matthew Crumley

2
@trusktr drawImageHiçbir şey yapmazsınız ve sonunda boş bir tuval ve sonuçta ortaya çıkan görüntü elde edersiniz.
Matthew Crumley

1
@JohnSewell Bunun nedeni sadece OP'nin bir URL değil içeriği istemesi. Bir görüntü kaynağı olarak kullanmak istiyorsanız, replace (...) çağrısını atlamanız gerekir.
Matthew Crumley

76

Bu İşlev URL'yi alır ve ardından BASE64 resmini döndürür

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

Buna şöyle deyin: getBase64FromImageUrl("images/slbltxt.png")


8
harici bağlantıdan 64 numaralı görüntüye çevirmenin bir yolu var mı?
dinodsaurus

@dinodsaurus bir resim etiketine yükleyebilir veya bir ajax sorgusu yapabilirsiniz.
Jared Forsyth

6
Eh, onların CORS uygulamasını gerektirir, ama sonra sadece $ .ajax (theimageurl) yaparsınız ve makul bir şey döndürmelidir. Aksi takdirde (CORS etkin değilse) çalışmaz; İnternetin güvenlik modeli buna izin vermiyor. Tabii ki, bir krom eklentisinin içinde olmadığınız sürece, bu durumda her şeye izin verilir - yukarıdaki örnek bile
Jared Forsyth

4
Sen koymak gerekir img.src =sonra img.onload =Opera gibi bazı tarayıcılarda, olay olmayacak çünkü.
ostapische

1
@Hakkar bir bellek sızıntısı yalnızca çöp toplama işlemini bilgilendirmek için hala referans sayısı kullanan eski tarayıcılarda gerçekleşir . Anladığım kadarıyla, dairesel referans bir işaret ve tarama kurulumunda . Bir kez fonksiyonların kapsamları getBase64FromImageUrl(url)ve img.onload = function ()çıkışları img ulaşılamaz ve çöp toplanır. IE 6/7 dışında ve bu tamam.
humanityANDpeace

59

Uzun zaman sonra geliyor, ama buradaki cevapların hiçbiri tamamen doğru değil.

Bir tuval üzerine çizildiğinde, iletilen görüntü sıkıştırılmamış + tümü önceden çoğaltılır.
Dışa aktarıldığında, farklı bir algoritma ile sıkıştırılmamış veya yeniden sıkıştırılmış ve çarpılmamış.

Tüm tarayıcılarda ve cihazlarda bu işlemde farklı yuvarlama hataları olacaktır.
(bkz. Kanvas parmak izi ).

Biri bir görüntü dosyasının base64 sürümünü istiyorsa, yeniden istemek (çoğu zaman önbellekten gelecektir) ama bu sefer bir Blob olarak.

Sonra bir ArrayBuffer veya dataURL olarak okumak için bir FileReader kullanabilirsiniz.

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


Sadece 5+ farklı soru gibi geçti ve kodunuz doğru çalışan tek kod, teşekkürler :)
Peter

1
Yukarıdaki kodu ile bu hatayı alıyorum. XMLHttpRequest cannot load data:image/jpeg;base64,/9j/4AA ... /2Q==. Invalid response. Origin 'https://example.com' is therefore not allowed access.
STWilson

2
@STWilson, evet, bu yöntem de tıpkı tuval gibi aynı köken politikasına bağlı. Çapraz kaynak talebi durumunda, barındırma sunucusunu komut dosyanız için bu çapraz kaynak taleplerine izin verecek şekilde yapılandırmanız gerekir.
Kaiido

@Kaiido böylece görüntü barındırma sunucusu çapraz kökenli istekleri etkinleştirmek için komut dosyası başka bir sunucuda ise? İmg.setAttribute ('crossOrigin', 'anonim') ayarlarsanız, bu hatayı önler mi?
1.21 gigawatts

1
Daha fazla araştırma yapıldığında, resmin erişim isteğinde bulunmak için crossOrigin özniteliğini kullanabileceği anlaşılıyor, ancak bir CORS üstbilgisi olan sitepoint.com/an-in-depth-look-at-cors üzerinden erişim vermek barındırma sunucusuna bağlı . XMLHttpRequest'e gelince, sunucunun bir CORS üstbilgisi aracılığıyla görüntülerle aynı erişimi vermesi gerekir, ancak kodunuzda xhr.withCredentials öğesini false (varsayılan) olarak ayarlamak dışında herhangi bir değişiklik gerekmez.
1.21 gigawatts

20

Kaiido'nun getirmeyi kullanarak cevabının daha modern bir versiyonu:

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

Düzenleme: Yorumlarda da belirtildiği gibi bu, gerçek bir DataURL yerine yerel sisteminizde bir dosyaya işaret eden bir nesne URL'si döndürür, bu nedenle kullanım durumunuza bağlı olarak ihtiyacınız olan şey olmayabilir.

Getirme ve gerçek verileri kullanmak için aşağıdaki cevaba bakabilirsiniz: URL: https://stackoverflow.com/a/50463054/599602


2
URL.revokeObjectURL()Bu yöntemi kullanarak uzun süredir çalışan bir uygulamanız varsa aramayı unutmayın , aksi takdirde belleğiniz karışacaktır.
Mühendis

1
Dikkat: DataURL (base64 kodlu) ObjectURL (blob referansı) ile aynı değil
DaniEll

1
ObjectURL kesinlikle veri URL'si değildir. Bu doğru bir cevap değil.
Danny Lin

2

shiv / shim / sham

Resimleriniz zaten yüklüyse (veya yüklenmediyse), bu "araç" kullanışlı olabilir:

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

.. ama neden?

Bunun "önceden yüklenmiş" görüntü verilerini kullanma avantajı vardır, bu nedenle ekstra bir istek gerekmez. Aditionally o son kullanıcıya (sizin gibi programcı) karar vermenizi sağlar CORS'yi ve / veya mime-typeve quality-VEYA- bu argümanlar / anlatıldığı gibi parametreler göz bırakabilir MDN şartname burada .

Bu JS yüklüyse (gerektiğinde), dönüştürmek dataURLşu kadar basittir:

örnekler

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

GPU parmak izi

Bitlerin "kesinliği" konusunda endişeleriniz varsa, bu aracı @ Kaiido'nun cevabının sağladığı şekilde ihtiyaçlarınıza göre değiştirebilirsiniz.


1

Yükledikten onloadsonra görüntüyü dönüştürmek için etkinliği kullanma


-3

HTML5'te şunu kullanın:

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

2
Soruyu cevaplarken daha spesifik olmaya çalışın ve ayrıntılı açıklamalar sağlayın.
Piyush Zalani
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.