웹 페이지에서 서버로 이미지 파일을 올려주기 전 이미지의 크기가 클 경우 리사이징 후 파일을 올려주고자 한다.
서버단에서도 조정할 수 있지만 서버에 무리가 올수 있기에 클라이언트단에서 처리하는 것이 좋다고 한다.
아래 두 주소는 코드를 참고한 사이트이다.
https://stackoverflow.com/questions/23945494/use-html5-to-resize-an-image-before-upload
https://codepen.io/tuanitpro/pen/wJZJbp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 | <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> </head> <body> <input type="file" name="file_name" id="file_name" multiple="multiple" /> <button type="button" id="upload" >upload</button> <img src="" id="preview" > <img src="" id="output"> <script src="https://code.jquery.com/jquery-3.2.1.min.js"></script> <script> var resizeImage = function (settings) { var file = settings.file; var maxSize = settings.maxSize; var reader = new FileReader(); var image = new Image(); var canvas = document.createElement('canvas'); var dataURItoBlob = function (dataURI) { var bytes = dataURI.split(',')[0].indexOf('base64') >= 0 ? atob(dataURI.split(',')[1]) : unescape(dataURI.split(',')[1]); var mime = dataURI.split(',')[0].split(':')[1].split(';')[0]; var max = bytes.length; var ia = new Uint8Array(max); for (var i = 0; i < max; i++) ia[i] = bytes.charCodeAt(i); return new Blob([ia], { type: 'image/jpeg'}); }; var resize = function () { var width = image.width; var height = image.height; if (width > height) { if (width > maxSize) { height *= maxSize / width; width = maxSize; } } else { if (height > maxSize) { width *= maxSize / height; height = maxSize; } } canvas.width = width; canvas.height = height; canvas.getContext('2d').drawImage(image, 0, 0, width, height); var dataUrl = canvas.toDataURL('image/jpeg'); return dataURItoBlob(dataUrl); }; return new Promise(function (ok, no) { if (!file.type.match(/image.*/)) { no(new Error("Not an image")); return; } reader.onload = function (readerEvent) { image.onload = function () { return ok(resize()); }; image.src = readerEvent.target.result; }; reader.readAsDataURL(file); }); }; let fileMap = new Map(); $(document).ready(function() { $("#file_name").on("change", select); $("#upload").off("click").on("click", upload); }); function select(){ $.each(this.files, function(index, file){ var reader = new FileReader(); reader.onload = function(e){ document.getElementById('preview').src = e.target.result; }; reader.readAsDataURL(file); // resizing 이전 파일 fileMap.set("1_"+file.name,file); resizeImage({ file: file, maxSize: 500 }).then(function (resizedImage) { reader.onload = function(e){ document.getElementById('output').src = resizedImage; }; reader.readAsDataURL(file); // resizing 이후 파일 fileMap.set("2_"+file.name,resizedImage); }); }); } function upload(){ console.log("fileMap : " + fileMap.size); console.log(fileMap); } </script> </body> </html> | cs |
1 2 3 4 5 | <input type="file" name="file_name" id="file_name" multiple="multiple" /> <button type="button" id="upload" >upload</button> <img src="" id="preview" > <img src="" id="output"> <script src="https://code.jquery.com/jquery-3.2.1.min.js"></script> | cs |
<script>
작동은
1. 파일 선택시 resizing 전과 후의 파일을 Map에 저장한다.
2. upload 파일을 보낸다. (이 코드는 console.log()로 확인을 위한 용도만 작성되어있다.)
1 2 3 4 | $(document).ready(function() { $("#file_name").on("change", select); $("#upload").off("click").on("click", upload); }); | cs |
ES6에서 추가된 Map이다.
다른 언어에서 사용하는 HashMap 과 동일하게 사용된다.
1 | let fileMap = new Map(); | cs |
아래 소스코드는 이미지 파일을 resizing하는 함수다.
settings에는 file과 maxSize 초기값을 추가해 함수로 보내준다.
dataURItoBlob : dataURI를 blob형태로 변환하기 위한 함수이다.
resize : 이미지 파일을 지정한 maxSize로 size를 조절해준다.
return new Promise(function (ok, no) { }; : ES6에서 추가된 Promise로 작업을 비동기 적으로 실행시키는 함수이다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | var resizeImage = function (settings) { var file = settings.file; var maxSize = settings.maxSize; var reader = new FileReader(); var image = new Image(); var canvas = document.createElement('canvas'); var dataURItoBlob = function (dataURI) { var bytes = dataURI.split(',')[0].indexOf('base64') >= 0 ? atob(dataURI.split(',')[1]) : unescape(dataURI.split(',')[1]); var mime = dataURI.split(',')[0].split(':')[1].split(';')[0]; var max = bytes.length; var ia = new Uint8Array(max); for (var i = 0; i < max; i++) ia[i] = bytes.charCodeAt(i); return new Blob([ia], { type: 'image/jpeg'}); }; var resize = function () { var width = image.width; var height = image.height; if (width > height) { if (width > maxSize) { height *= maxSize / width; width = maxSize; } } else { if (height > maxSize) { width *= maxSize / height; height = maxSize; } } canvas.width = width; canvas.height = height; canvas.getContext('2d').drawImage(image, 0, 0, width, height); var dataUrl = canvas.toDataURL('image/jpeg'); return dataURItoBlob(dataUrl); }; return new Promise(function (ok, no) { if (!file.type.match(/image.*/)) { no(new Error("Not an image")); return; } reader.onload = function (readerEvent) { image.onload = function () { return ok(resize()); }; image.src = readerEvent.target.result; }; reader.readAsDataURL(file); }); }; | cs |
하단의 소스는 선택한 파일을 resizing 이전과 이후 두개의 데이터를 fileMap 에추가한다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | function select(){ $.each(this.files, function(index, file){ var reader = new FileReader(); reader.onload = function(e){ document.getElementById('preview').src = e.target.result; }; reader.readAsDataURL(file); // resizing 이전 파일 fileMap.set("1_"+file.name,file); resizeImage({ file: file, maxSize: 500 }).then(function (resizedImage) { reader.onload = function(e){ document.getElementById('output').src = resizedImage; }; reader.readAsDataURL(file); // resizing 이후 파일 fileMap.set("2_"+file.name,resizedImage); }); }); } | cs |
하단의 소스는 'preview' 태그에 이미지 src를 변경한다. (즉 이미지를 띄운다.)
resizeImage() 함수는 file과 maxsize의 초기값을 함수로 넘겨준다.
then은 Promise 사용시 사용하는 함수이다.
간단히 설명하자면 Promise를 사용한 비동기 작업 완료 후 .then()가 실행된다.
주로 chain형태로 연결되어있다.
추가설명
※ 선택한 파일이 이미지일 경우만 resizing하고 싶다면 아래 조건을 추가
1 2 3 4 | // image파일만 가져와서 실행 if(file.type.match(/image.*/)){ }; | cs |
※ 일정 크기 이상만 resizing을 실행하고 싶다면 아래 조건을 추가
1 2 3 | if (file.size > 204800){ }; | cs |
※ file을 서버로 보내고 싶다면 FormData() 로 저장 후 보내자. (ajax 사용시 data 부분에 formData를 보내주면 된다.)
※ 다른 데이터도 함께 보내고 싶을 경우 serializeObject()를 이용하자.
※ Service 쪽에서는 MultipartHttpServletRequest request를 이용해 사용하도록 하자.
1 2 3 4 5 | List<MultipartFile> file_list = request.getFiles("file_name"); for(int i=0;i<file_list.size();i++){ MultipartFile multipartFile = file_list.get(i); }; | cs |
※ Blob은 API들 간에 데이터를 교환하기 위해 사용하는 불투명(opaque) 타입이다.
※ ES6는 ECMAScript 6 로 2015년 6월에 발표된 javascript 개정판이다.
'Front-End > JavaScript' 카테고리의 다른 글
[JavaScript] IE에서 Audio 사용하기 (0) | 2019.05.21 |
---|---|
[JavaScript] 달력 만들기 (5) | 2018.10.08 |