이 글은 Creating thumbnails with drag and drop and HTML5 canvas 을 번역한 글입니다.
HTML5 캔버스는 뛰어난 특징을 가지고 있다. 겉보기에는 브라우저 내에서 저수준의 API를 이용하여 그림을 그리는 것뿐이지만 실제로는 이를 이용하여 이미지나 문서 내 비디오 컨텐츠를 조정하거나 변경할 수 있다. 이제 캔버스를 이용하여 브라우저 문서 안에 있는 이미지의 섬네일을 생성하기 위해 사용하는 FileReader API에 대해 살펴볼 것이다. 최종 코드는 [Github]에 올려져 있고 [온라인 데모]도 확인할 수 있다. YouTube에는 화면 캡춰도 올려져 있다.
1단계: 브라우저에서 파일 얻어내기
브라우저 내의 이미지 크기를 조정하기 위해 우선 첫 번째로 어떻게든 이미지를 가져와야 한다. 그래서 페이지에 엘리먼트를 추가해서 드래그 앤 드롭 이벤트 핸들러를 설정한다.
s.addEventListener( 'dragover', function ( evt ) { evt.preventDefault(); }, false ); s.addEventListener( 'drop', getfiles, false );
엘리먼트 위의 무언가를 드래그할 때 기본 동작을 하지 않는 코드를 추가했다. 그 이유는 이미지를 드래그했을 때 브라우저에서 이미지를 보여주지 않기 위해서이다. 그리고나서 문서 내 모든 파일을 읽어서 이미지 리사이징과 섬네일 생성을 하도록 전달하는 getfile()함수를 추가한다.
function getfiles( ev ) { var files = ev.dataTransfer.files; if ( files.length > 0 ) { var i = files.length; while ( i-- ) { var file = files[ i ]; if ( file.type.indexOf( 'image' ) === -1 ) { continue; } var reader = new FileReader(); reader.readAsDataURL( file ); reader.onload = function ( ev ) { var img = new Image(); img.src = ev.target.result; img.onload = function() { imagetocanvas( this, thumbwidth, thumbheight, crop, background ); }; }; } } ev.preventDefault(); };
드롭 이벤트의 dataTransfer 속성에는 드롭된 모든 파일 목록을 포함하고 있어서 적어도 1개 이상의 파일이 있고 그 이상일 경우 반복해서 가져올 수 있다.
파일 중 이미지가 아닌 파일이 있다면 (다시 말해 파일 타입에 ‘image’라는 문자열을 포함하고 있지 않다면) 아무것도 할 필요가 없고 다음 파일을 탐색하면 된다.
이미지 파일이라면 새로운 FileReader의 인스턴스로 생성하여 Data URL로서 파일을 조회할 수 있도록 한다.
새로운 이미지를 생성한 후에 이미지를 로드할 때 전달받은 값으로 src 속성값을 설정한다. 그리고나서 그 이미지를 리사이즈할 값과 함께 imagetocanvas() 함수를 호출할 때 파라미터로 전달한다. (데모에서는 form 값으로 전달한다)
function imagetocanvas( img, thumbwidth, thumbheight, crop, background ) { c.width = thumbwidth; c.height = thumbheight; var dimensions = resize( img.width, img.height, thumbwidth, thumbheight ); if ( crop ) { c.width = dimensions.w; c.height = dimensions.h; dimensions.x = 0; dimensions.y = 0; } if ( background !== 'transparent' ) { cx.fillStyle = background; cx.fillRect ( 0, 0, thumbwidth, thumbheight ); } cx.drawImage( img, dimensions.x, dimensions.y, dimensions.w, dimensions.h ); addtothumbslist( jpeg, quality ); };
imagetocanvas() 함수에서는 파라미터로 전달받은 크기로 캔버스 크기를 조절하면서 기존 이미지가 섬네일에 더해지지 않도록 캔버스를 정리한다. 그리고나서 resize()함수를 이용하여 사이즈에 맞게 이미지를 리사이즈한다. 소스 코드에서 무엇을 하는지 확인할 수 있듯이, 단지 이미지를 사이즈에 맞게 조정할 뿐이다. 이 함수를 사용하면 새로운 이미지 객체와 그 이미지가 위치할 캔버스 위의 x/y 좌표를 반환한다.
만약 전체 크기의 섬네일이 필요없다면 캔버스를 잘라내지 않고 x/y좌표를 0으로 초기화해서 캔버스 사이즈를 조정하면 된다.
배경화면이 필요하면 캔버스에 색깔을 입히면 된다. 그 이후에 캔버스에 이미지와 함께 x/y좌표와 width/height를 전달하면 된다.
여태까지 캔버스에 새로운 이미지를 생성하는 것에만 신경썼지만 아직 새로운 이미지를 얻어온 것은 아니다. 마지막에 addtothumbslist() 함수를 호출해야 한다.
function addtothumbslist( jpeg, quality ) { var thumb = new Image(), url = jpeg ? c.toDataURL( 'image/jpeg' , quality ) : c.toDataURL(); thumb.src = url; thumb.title = Math.round( url.length / 1000 * 100 ) / 100 + ' KB'; o.appendChild( thumb ); };
이 함수에서 새로운 이미지를 생성할 때 사용자가 JPG/PNG이미지를 원하는지 확인하도록 한다. 만약 PNG라면 이미지 품질은 좀 더 좋아지겠지만 파일 크기는 상대적으로 커질 것이다. JPG라면 캔버스의 toDataURL() 함수를 호출하면서 2개의 파라미터를 전달하는데 하나는 JPEG mime type이고 또 하나는 이미지 품질을 의미한다. (0-1사이의 값을 설정하고, 1인 경우 가장 좋은 품질을 의미한다.) PNG포맷을 원한다면 기본값으로 파라미터 없이 toDataURL() 함수를 호출하면 된다.
이미지 src값을 url 형태의 문자열로 생성하고 제목에 소수점 2자리 반올림 한 이미지 용량을 KB단위로 보여준다. 이제 섬네일을 페이지 위의 결과 엘리먼트에 더하면 된다.
이렇게 하면 끝이다. 이제 바로 브라우저 안의 이미지를 드래그 앤 드롭하여 섬네일을 만들 수 있고 그걸 저장하거나 다운로드한 이미지들을 한번에 얻을 수도 있다). Zip.js를 추가하여 zip파일로 만들수도 있으니 이 글을 읽는 독자는 아마도 시도해볼 것 같다. 🙂
더 읽을거리:
- 드래그 앤 드롭 MDN 문서
- FileReader MDN 문서
- Canvas MDN 문서
1개 댓글