HTML5에는 정말 놀라운 API들이 포함 돼 있습니다. 이러한 API를 <canvas> 엘리먼트와 조합하면, 강력하고 현대적이며 놀라운 이미지 업로더를 만들 수 있습니다. 이 글은 그런 이미지 업로더를 만드는 방법을 설명합니다.
여기에서 소개하는 모든 팁들은 Firefox 4에서 잘 동작합니다. 또한 웹킷 기반의 브라우저들에서도 문제없이 동작하는 대체 방법들도 기술하였습니다. API의 대부분은 IE에서는 동작하지 않지만, 그에 대한 대비책으로 일반적인 폼을 사용하는 것은 매우 쉽습니다.
여러분이 만약 이러한 기술들 중 하나를 자신의 프로젝트에 사용하게 된다면 우리에게 알려주시기 바랍니다.
이미지 읽기
드래그 앤 드롭
파일을 업로드 하기 위해서는 <input type=”file”> 엘리먼트가 필요합니다. 하지만, 사용자가 데스크톱에서 웹 페이지로 이미지를 드래그 앤 드롭하게 하는 것도 지원하는 것이 좋습니다.
드래그 앤 드롭에 대한 자세한 내용은 제가 이전에 작성한 드래그 앤 드롭을 지원하는 웹 페이지 구현에 설명돼 있습니다.
또한, 모질라 튜토리얼의 드래그 앤 드롭을 살펴보는 것도 도움이 됩니다.
다중 input
사용자가 파일 선택 창에서 업로드할 파일을 동시에 여러개 선택할 수 있습니다.
<input type="file" multiple>
Again, here is an article I’ve written about multiple file selection.
다중 파일 선택과 관련해서도 다중 파일 선택이라는 제가 작성한 글이 있습니다.
파일 전처리
File API 사용
(자세한 내용은 File API 문서를 참조하세요)
드래그 앤 드롭이나 <input> 엘리먼트로 부터 선택된 파일 목록을 다음과 같은 방법으로 얻을 수 있습니다.
// input 엘리먼트에서 var filesToUpload = input.files; // 드래그 앤 드롭 function onDrop(e) { filesToUpload = e.dataTransfer.files; }
선택된 파일들이 실제 이미지들인지 확인합니다.
if (!file.type.match(/image.*/)) { // 이미지가 아닌 파일 };
썸네일(미리보기) 보여주기
두가지 옵션이 있습니다. 파일 API의 FileReader 를 사용하거나, 새로운 createObjectURL()
메소드를 사용할 수 있습니다.
createObjectURL()
var img = document.createElement("img"); img.src = window.URL.createObjectURL(file);
FileReader
var img = document.createElement("img"); var reader = new FileReader(); reader.onload = function(e) {img.src = e.target.result} reader.readAsDataURL(file);
캔버스 사용
일단 <img> 엘리먼트에 이미지 미리보기를 하면, 이 이미지를 파일 전처리를 위해 <canvas> 엘리먼트에 그릴 수 있습니다.
var ctx = canvas.getContext("2d"); ctx.drawImage(img, 0, 0);
이미지 크기 조절
사용자들은 카메라에서 찍은 이미지를 그대로 업로드 하는 데 익숙합니다. 이런 이미지들은 매우 고 해상도 이고 아주 크기가 큰 파일들입니다(수 메가 바이트). 용도에 따라 이런 이미지들의 크기를 조절하기를 원할 수 있습니다. 아주 간단한 트릭은 작은 캔버스(예를 들어 800×600)를 준비하고, 이미지 태그를 이 캔버스에 그리는 것입니다. 물론 이미지의 비율을 유지하기 위해서 캔버스의 크기(dimensions)를 변경해야 합니다.
var MAX_WIDTH = 800; var MAX_HEIGHT = 600; var width = img.width; var height = img.height; if (width > height) { if (width > MAX_WIDTH) { height *= MAX_WIDTH / width; width = MAX_WIDTH; } } else { if (height > MAX_HEIGHT) { width *= MAX_HEIGHT / height; height = MAX_HEIGHT; } } canvas.width = width; canvas.height = height; var ctx = canvas.getContext("2d"); ctx.drawImage(img, 0, 0, width, height);
이미지 편집
이제 이미지를 캔버스에 올렸습니다. 기본적으로, 할 수 있는 일은 무궁무진합니다. 예를 들어 세피아 필터를 적용하고 싶다면 다음과 같이 하면 됩니다.
var imgData = ctx.createImageData(width, height); var data = imgData.data; var pixels = ctx.getImageData(0, 0, width, height); for (var i = 0, ii = pixels.data.length; i < ii; i += 4) { var r = pixels.data[i + 0]; var g =pixels.data[i + 1]; var b = this.pixels.data[i + 2]; data[i + 0] = (r * .393) + (g *.769) + (b * .189); data[i + 1] = (r * .349) + (g *.686) + (b * .168) data[i + 2] = (r * .272) + (g *.534) + (b * .131) data[i + 3] = 255; } ctx.putImageData(imgData, 0, 0);
XMLHttpRequest를 사용하여 업로드
클라이언트에 이미지를 적재했으니, 다음은 이를 서버로 전송하는 것입니다.
캔버스를 전송하는 방법
또 다시 두 가지 옵션이 있습니다. 캔버스를 데이터 URL로 변환 할 수도 있고, (Firefox 상에서) 캔버스를 이용해 파일을 생성할 수도 있습니다.
canvas.toDataURL()
var dataurl = canvas.toDataURL("image/png");
캔버스를 이용하여 파일 생성
var file = canvas.mozGetAsFile("foo.png");
유연한 업로드
사용자에게 하나의 파일이나 또는 선택한 파일 전체를 한 번에 업로드할 수 있게 합니다.
업로드 진행상황 보여주기
프로그레스바를 생성하기 위해서 업로드 이벤트를 사용합니다.
xhr.upload.addEventListener("progress", function(e) { if (e.lengthComputable) { var percentage = Math.round((e.loaded * 100) / e.total); // 필요한 작업 수행 }, false);
FormData 사용
여러분은 단지 (xhr.send(file)
를 사용하여 쉽게 할 수 있는) 파일만 업로드 하는 것을 원하지 않을 것이며, 아마 (키와 이름 같은)부가적인 정보를 추가하여 업로드 하는 것을 원할 것입니다.
이런 경우, FormData
객체를 사용하여 multipart/form-data
요청을 생성하는 것이 필요합니다(Firefox 4: FormData를 사용하여 JS로 보다 쉽게 폼 다루기 참조).
var fd = new FormData(); fd.append("name", "paul"); fd.append("image", canvas.mozGetAsFile("foo.png")); fd.append("key", "××××××××××××"); var xhr = new XMLHttpRequest(); xhr.open("POST", "http://your.api.com/upload.json"); xhr.send(fd);
자신의 API를 공개하는 방법
자신의 서비스를 다른 웹사이트에서 사용하도록 허용하기를 원할 수 있습니다.
교차 도메인 요청 허용
기본적으로 여러분의 API는 자신의 도메인으로부터 오는 요청만 허용할 것입니다. 만약에, 사람들이 여러분의 API를 사용하도록 허락하려면, 다음과 같은 HTTP 헤더를 추가하여 교차 XHR를 허용하면 됩니다.
Access-Control-Allow-Origin: *
또한 미리 지정한 도메인들만 허용할 수도 있습니다.
교차 사이트 자원 공유를 읽어보기 바랍니다.
postMessage
(이 팁과 관련하여 다니엘 굳윈에게 감사를 전합니다.)
또한, postMessage
를 통해 보낸 메시지를 수신할 수 있습니다. 사용자가 다음과 같이 postMessage를 통해서 여러분의 API를 사용하도록 할 수 있습니다.
document.addEventListener("message", function(e){ // e.data에서 인수 읽기 var key = e.data.key; var name = e.data.name; var dataurl = e.data.dataurl; // 업로드 } // 일단 업로드가 완료되면 원래의 창에 postMessage를 보낼 수 있음
여기까지입니다. 이와 관련하여 공유할만한 다른 팁이 있는 분은 자유롭게 댓글을 남겨 주세요.
Enjoy 😉
원저자: Paul Rouget – 원문으로 가기
2 댓글