Graceful Light

javascript로 로컬에 이미지 다운로드

2017-01-16


버튼을 눌러 이미지를 다운로드 받고 싶다면 어떻게 해야될까?
Client Side에서 할 수 있는 가장 쉬운 방법은 download attribute를 사용하는 것이다.
하지만 예상했듯이 이 속성은 IE에서 지원하지 않는다.

For IE

base64

먼저 이미지를 base64 인코딩해야한다.
FileReader 또는 Canvas를 이용해 변환할 수 있는데 stackoverflow의 명쾌한 답변을 참조하자.
jQuery 환경이라면 Reading binary data using jquery ajax를 참조해도 된다.

base64encode가 된 이미지 데이터가 뽑아지면 시작할 수 있다.

1
data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAPYAAAD2CAAAAADAeSUUAAADN0lEQVR42u3aQY7CMBAEQP7/afaKtEu2exwk4lROKITEZSQGT/vxiI/ny/H7zOv513ffXZl89viad6M6+cDGxsa+CDsZUP5uMqx3d8gntB3nH1ODjY2NvR373S/88TUtMuG1E5qMExsbGxv7eChJUTl+4nP5wMbGxsZu2UlbJy9RyQS1SxpsbGzsu7FXCkPeTkoihGTQeUPqhF4aNjY29tez81T0+19/JN/GxsbG/mL2rHEzi2OTxc968BwpsLGxsTdiz0Lc/I9+voBprzwhhMbGxsbeiN1S2xvNWkuzZtD6aLGxsbGvxW4f0BaqtpU/C4/bhRA2Njb2TuwkTF0ZVn4+/+zKJEb7lbCxsbG3YM9aRe0CJo8NkivzFhU2Njb2ruwW3/71r0vL6FnDXUvY2NjYl2XPAto8mm0LUrIImcUG2NjY2Luy1xv6eTCwMomzAlZPEzY2NvbF2ceDWIld82XJSjjRbsfExsbG3om9EgbkDak2GM5L6bApho2Njb0F+/imeclJWj/t61nwEBU2bGxs7I3Yn2vifKLN1MKKxQk2Njb2ZdlnFYzZ9bMG00rbCxsbG/sO7Lw13261zIvlMXVW5B7tDGFjY2NvwZ4lpDmpLYenXYmNjY29ETv5u5+XkDYYaFtL7ZKm2KmEjY2NfVl2u10mWYS009q2hNoC9scZbGxs7I3YM+SsjJ3V0lqZ3MfKd4uNjY39lexk6Hlkm4fHs40+7dacomhhY2Njb8TOi1MeCZw7oflER1t2sLGxsS/Onq1d2hC3XYq0japZCIGNjY29K7u9Xds8WmlU5SWwiH6xsbGxt2DnP/dthNBS12FFScPGxsbelN02aNrFRh4tzJ5SbO7BxsbGvgE7Aa8EACvlc6X9hI2Njb0T+1keySBmm3jy0Le92z9JCDY2NvbF2W0BOLfwHJ9vW0v1UgQbGxt7I3ZStFbKTLKMab+TZFH0T+SAjY2NvR07b7vP4ti2TK5MSvRcbGxs7Nuz2wfnT1nZalncBxsbG/vG7PWtlmdt5VlpimFjY2Pvx06aRHlBarfs5O3+9ut5u/rAxsbG3og9W1TkxWYWP7T3zBtV2NjY2BuxfwBOAYaS/PUQNQAAAABJRU5ErkJggg==

blob

이제 이미지 데이터를 Blob Object로 변환해야한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
// imageSrc는 위의 이미지 데이터이다.
// 실제 데이터는 iVBO...부터이므로 split한다.
var imgData = atob(imageSrc.split(',')[1]);
var len = imgData.length;
var buf = new ArrayBuffer(len); // 비트를 담을 버퍼를 만든다.
var view = new Uint8Array(buf); // 버퍼를 8bit Unsigned Int로 담는다.
var blob, i;
for (i = 0; i < len; i++) {
view[i] = imgData.charCodeAt(i) & 0xff; // 비트 마스킹을 통해 msb를 보호한다.
}
// Blob 객체를 image/png 타입으로 생성한다. (application/octet-stream도 가능)
blob = new Blob([view], {type: 'image/png'});

msSaveOrOpenBlob

IE10+ 에서 사용가능한 msSaveOrOpenBlob가 필요하다.

msSaveBlob 메서드는 저장 단추만 사용자에게 제공하는 반면
msSaveOrOpenBlob 메소드는 저장 및 열기 단추를 모두 제공한다는 것이 차이점이다.

1
2
// blob과 저장될 파일명을 받는다.
window.navigator.msSaveOrOpenBlob(blob, "new_file_name.png");

Not IE

IE가 세상에 존재하지 않는다면 코드는 아주 예쁘게 짤 수 있다.

1
2
3
<a href="data:image/png;base64,iVBORw0KG..." download="new_file_name.png">
<img src="data:image/png;base64,iVBORw0KG..."/>
</a>

a 태그가 보기 싫다면 아래 구문을 포함해 함수로 만든다.

1
2
3
4
5
6
7
8
9
10
11
var a = document.createElement('a');
a.style = "display: none";
a.href = img.src;
a.download = "new_file_name.png";
document.body.appendChild(a);
a.click();
setTimeout(function() { // 다운로드가 안되는 경우 방지
document.body.removeChild(a);
}, 100);

Blob 재사용

IE 때문에 만들었던 Blob 객체를 URL 기능을 이용해 재사용해보자.

1
2
3
4
5
6
7
8
9
10
11
12
13
var url = URL.createObjectURL(blob);
var a = document.createElement('a');
a.style = "display: none";
a.href = url;
a.download = "new_file_name.png";
document.body.appendChild(a);
a.click();
setTimeout(function(){
document.body.removeChild(a);
URL.revokeObjectURL(url); // 메모리 해제
},100);

소스

여담

🍺

Buy me a beer 🍗

공유하려면 QR코드를 스캔해주세요