it-swarm-vi.com

Lấy dữ liệu hình ảnh trong JavaScript?

Tôi có một trang HTML thông thường với một số hình ảnh (chỉ là các thẻ HTML <img /> thông thường). Tôi muốn có được nội dung của họ, tốt nhất là mã hóa 64, mà không cần tải lại hình ảnh (tức là nó đã được trình duyệt tải, vì vậy bây giờ tôi muốn nội dung).

Tôi muốn đạt được điều đó với Greasemonkey và Firefox.

310
Detariael

Lưu ý: Điều này chỉ hoạt động nếu hình ảnh từ cùng một tên miền với trang hoặc có thuộc tính crossOrigin="anonymous" và máy chủ hỗ trợ CORS. Nó cũng sẽ không cung cấp cho bạn tệp gốc mà là phiên bản được mã hóa lại. Nếu bạn cần kết quả giống hệt với bản gốc, hãy xem Câu trả lời của Kaiido .


Bạn sẽ cần tạo một thành phần canvas với kích thước chính xác và sao chép dữ liệu hình ảnh với chức năng drawImage. Sau đó, bạn có thể sử dụng hàm toDataURL để lấy dữ liệu: url có hình ảnh được mã hóa cơ sở 64. Lưu ý rằng hình ảnh phải được tải đầy đủ, hoặc bạn sẽ chỉ nhận lại được một hình ảnh trống (đen, trong suốt).

Nó sẽ là một cái gì đó như thế này. Tôi chưa bao giờ viết tập lệnh Greasemonkey, vì vậy bạn có thể cần điều chỉnh mã để chạy trong môi trường đó.

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

Nhận hình ảnh có định dạng JPEG không hoạt động trên các phiên bản cũ hơn (khoảng 3,5) của Firefox, vì vậy nếu bạn muốn hỗ trợ điều đó, bạn sẽ cần kiểm tra tính tương thích. Nếu mã hóa không được hỗ trợ, nó sẽ mặc định là "image/png".

387
Matthew Crumley

Hàm này lấy URL sau đó trả về hình ảnh 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;
}

Gọi nó như thế này: getBase64FromImageUrl("images/slbltxt.png")

73
MuniR

Đến rất lâu sau đó, nhưng không có câu trả lời nào ở đây là hoàn toàn chính xác.

Khi được vẽ trên một khung vẽ, hình ảnh đã qua không bị nén + tất cả được nhân lên trước.
Khi được xuất, nó không được nén hoặc được nén lại bằng một thuật toán khác và không được nhân.

Tất cả các trình duyệt và thiết bị sẽ có các lỗi làm tròn khác nhau xảy ra trong quá trình này
(xem Dấu vân tay Canvas ).

Vì vậy, nếu ai đó muốn có phiên bản base64 của tệp hình ảnh, họ phải request nó một lần nữa (hầu hết thời gian nó sẽ đến từ bộ đệm) nhưng lần này là Blob. 

Sau đó, bạn có thể sử dụng FileReader để đọc nó dưới dạng ArrayBuffer hoặc dưới dạng 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">

40
Kaiido

Ngoài câu trả lời của matthew, tôi muốn nói rằng image.ference và image.height trả lại kích thước hiển thị của hình ảnh (và cắt hình ảnh khi vẽ nó vào khung vẽ)

Thay vào đó, sử dụng NaturalWidth và NaturalHeight, sử dụng hình ảnh kích thước thật.

Xem http://www.whatwg.org/specs/web-apps/civerse-work/multipage/edits.html#dom-img-naturalference

22
cube45

Một phiên bản hiện đại hơn của câu trả lời của kaiido bằng cách sử dụng fetch sẽ là:

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

Sử dụng sự kiện onload để chuyển đổi hình ảnh sau khi tải

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
Kamil Kiełczewski

Trong HTML5, sử dụng tốt hơn điều này:

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