JavaScript로 이미지 데이터 URL을 가져 오시겠습니까?


335

일부 이미지가있는 일반 HTML 페이지가 있습니다 (일반 <img />HTML 태그 만). 이미지를 다시 다운로드 할 필요없이 base64로 인코딩 된 내용을 원합니다 (즉, 이미 브라우저에 의해로드되어 있으므로 내용을 원합니다).

Greasemonkey와 Firefox를 사용하여 달성하고 싶습니다.

답변:


400

참고 : 이미지가 페이지와 동일한 도메인에 있거나 crossOrigin="anonymous"속성이 있고 서버가 CORS를 지원하는 경우에만 작동합니다 . 또한 원본 파일이 아니라 다시 인코딩 된 버전을 제공합니다. 결과가 원본과 동일해야하는 경우 Kaiido의 답변을 참조하십시오 .


올바른 치수의 캔버스 요소를 작성하고 drawImage함수를 사용 하여 이미지 데이터를 복사해야 합니다. 그런 다음이 toDataURL함수를 사용 하여 base-64로 인코딩 된 이미지가있는 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로 된 이미지는 더 작으며 정확히 동일하게 사랑합니다. 한 가지 더 : 입력 이미지는 작은 배경 (594 바이트), 투명한 배경의 28x30 PNG입니다.
Detariael

7
Firefox는 다른 압축 수준을 사용하여 인코딩에 영향을 줄 수 있습니다. 또한 PNG는 노트와 같은 추가 헤더 정보를 지원한다고 생각합니다. 캔버스는 픽셀 데이터 만 가져 오기 때문에 손실 될 것입니다. 정확히 동일해야하는 경우 AJAX를 사용하여 파일을 가져 와서 base64로 수동으로 인코딩 할 수 있습니다.
Matthew Crumley

7
예, XMLHttpRequest로 이미지를 다운로드합니다. 바라건대, 이미지의 캐시 된 버전을 사용하지만 서버 및 브라우저 구성에 따라 달라 지므로 파일이 변경되었는지 확인하기 위해 요청 오버 헤드가 발생합니다. 그렇기 때문에 처음에는 다음과 같이 제안하지 않았습니다. :-) 불행히도, 아는 한, 원본 파일을 얻는 유일한 방법입니다.
Matthew Crumley

2
@trusktr drawImage아무것도하지 않으며 빈 캔버스와 결과 이미지가 생깁니다 .
Matthew Crumley

1
@JohnSewell OP가 URL이 아닌 콘텐츠를 원했기 때문입니다. 이미지 소스로 사용하려면 replace (...) 호출을 건너 뛰어야합니다.
Matthew Crumley

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
외부 링크에서베이스 64로 이미지를 전환하는 방법이 있습니까?
dinodsaurus

@dinodsaurus 이미지 태그에로드하거나 아약스 쿼리를 수행 할 수 있습니다.
Jared Forsyth

6
CORS를 구현해야하지만 $ .ajax (theimageurl)를 수행하면 합리적인 것을 반환해야합니다. 그렇지 않으면 (COR을 사용하지 않는 경우) 작동하지 않습니다. 인터넷의 보안 모델은 그것을 허용하지 않습니다. ,하지 않는 한 물론, 당신의 경우 모든 것이 허용되는 크롬 플러그인있는 거 내부 - 심지어 위의 예
자레드 포 시스를

4
Opera와 같은 일부 브라우저에서는 이벤트가 발생하지 않으므로, img.src =뒤에 넣어야합니다 img.onload =.
ostapische

1
@Hakkar 메모리 누수는 가비지 수집을 알리기 위해 여전히 참조 횟수 를 사용하는 오래된 브라우저에서만 발생합니다 . 이해하기 위해 원형 참조는 마크 및 스윕 설정 에서 누출을 생성하지 않습니다 . 함수의 범위 getBase64FromImageUrl(url)img.onload = function ()종료 되면 img에 도달 할 수없고 가비지 수집됩니다. IE 6/7 이외의 이것은 괜찮습니다.
humanandANDpeace

59

오래지 않아 왔지만 여기에 대한 대답은 전적으로 정확하지 않습니다.

캔버스에 그릴 때 전달 된 이미지는 압축되지 않은 + 모든 미리 곱셈됩니다.
내보낼 때 다른 알고리즘으로 압축 또는 재 압축 된 후 곱하지 않습니다.

이 과정에서 발생하는 모든 브라우저 및 장치에 다른 반올림 오류가 발생합니다
( 캔버스 지문 참조 ).

따라서 이미지 파일의 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+ 같은 다른 문제를 통과하고 코드가 제대로 작동 년대 단 하나, 감사합니다 :)입니다
피터

1
위의 코드 로이 오류가 발생합니다. XMLHttpRequest cannot load data:image/jpeg;base64,/9j/4AA ... /2Q==. Invalid response. Origin 'https://example.com' is therefore not allowed access.
STWilson

2
@STWilson, 예,이 방법은 캔버스와 마찬가지로 동일한 출처 정책에 연결되어 있습니다. 교차 출처 요청의 경우 이러한 교차 출처 요청을 스크립트에 허용하도록 호스팅 서버를 구성해야합니다.
Kaiido

@Kaiido 그래서 이미지가 스크립트가 아닌 다른 서버에 있다면 호스팅 서버는 원본 간 요청을 활성화해야합니까? img.setAttribute ( 'crossOrigin', 'anonymous')를 설정하면 오류가 발생하지 않습니까?
1.21 기가 와트

1
더 많은 연구 결과, image는 crossOrigin 속성을 사용하여 액세스를 요청할 수 있지만 CORS 헤더 sitepoint.com/an-in-depth-look-at-cors를 통해 액세스를 제공하는 것은 호스팅 서버에 달려 있습니다. XMLHttpRequest의 경우 서버는 CORS 헤더를 통해 이미지와 동일한 액세스 권한을 부여해야하지만 xhr.withCredentials를 false (기본값)로 설정하는 것을 제외하고는 코드를 변경할 필요가 없습니다.
1.21 기가 와트

20

fetch를 사용하는 최신 Kaikai 답변은 다음과 같습니다.

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이 아닙니다. 정답이 아닙니다.
Danny Lin

2

v / 심 / 샴

이미지가 이미로드되었거나로드되지 않은 경우이 "도구"가 유용 할 수 있습니다.

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및 / 또는 여기서 MDN 사양에 quality설명 된대로 이러한 인수 / 매개 변수를 생략 할 수 있습니다 .

이 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 2012 년
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.