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.