Develop!/script, Ajax

HTML5 Canvas를 이용한 브라우저에서 이미지 용량 줄이기

체리필터 2016. 11. 9. 12:01
728x90
반응형

이 역시 티몬 구매후기에서 이미지 업로드와 관련된 기능을 적용하면서 나온 내용을 정리 차원에서 적어 둡니다.

 

구매후기 작성 시 이미지를 선택해서 업로드를 하게 되는데, 기존에는 이미지의 사이즈를 제한하는 기능이 있었고 이로 인해 이미지 제한에 걸려 이미지를 업로드 하지 못하거나, 업로드 된 원본 이미지도 용량이 너무 큰 문제가 있었습니다. (장당 3MB)

 

아무런 제약 없이 이용자는 이미지를 마음껏 올릴 수 있으려면 이미지 리사이즈가 필요한데, 서버단에서 용량 리사이징을 하게 되면 아까운 네트웍 비용이 들어가게 되므로 클라이언트 단에서 용량을 줄일 필요가 있었습니다.

그래서 사용하게 된 것이 HTML5의 Canvas 기능이죠.

물론 이전에 HTML5를 제대로 사용해 본 적이 없어서...

모든 기능은 최고의 방법이 구글링을 통해 적용했습니다.

그리고 HTML5의 Canvas가 적용되지 않는 브라우저를 위해서라도 (망할 IE -.-;;) 기존 소스 코드는 남겨두고 분기 처리를 해야 했습니다.

 

기본적으로 jQuery를 사용 했습니다.

아... 그리고 기본적으로 저는 자바스크립트를 잘 못하는 개발자이므로 발코딩이 나와도 이해해 주세요 ^^

간단한 설명은 주석으로 달았습니다.

// html5의 Canvas를 사용해서 이미지 리사이징이 가능한지 판별하는 메소드
function isImageResizable() {
	var isCanvasUsable = !!document.createElement('canvas').getContext;
	var isLowerIE = false;

	if($.browser.msie) {
		if($.browser.version < 10) {	// IE9은 Canvas는 쓸 수 있지만 file input에서 file Object를 가져오지 못해 제외
			isLowerIE = true;
		}
	}

	return isCanvasUsable && !isLowerIE;
}

<html5의 Canvas를 사용해서 이미지 리사이징이 가능한지 판별하는 메소드>

 

<!-- file input을 form 밖에 두는 이유는 리사이징 한 내용을 동적으로 form 안에 넣어 submit 하기 위함 -->
<a href="#">사진등록<input type="file" name="Filedata" title="사진등록" id="_inputFile"></a>
<form id="_imageUploadForm" method="post" action="Action Url 입력" enctype="multipart/form-data">
<input type="hidden" id="file_name" name="file_name" value="" />
</form>

<html form>

 

// fileInput Object에 값이 변경될 때
welInputUpload.change(function(){
	// 이미지 리사이즈 가능한 브라우져가 아니라면 일반적인 업로드로...
	if(isImageResizable() == false) {
		$("#fileSelector").appendTo("#_imageUploadForm");
		welUploadForm.submit();
	} else {	// 이미지 리사이즈가 브라우저단에서 가능하다면 html5 사용...
		var file = welInputUpload.prop('files')[0];	// file Object get... 
		if(file.type.match(/image.*/)) {
			// Load the image
			var reader = new FileReader();
			reader.onload = function (readerEvent) {
				var image = new Image();
				image.onload = function (imageEvent) {

					// Resize the image
					var canvas = document.createElement('canvas'),
					max_size = 1280,
					width = image.width,
					height = image.height;

					if (width > height) {
						if (width > max_size) {
							height *= max_size / width;
							width = max_size;
						}
					} else {
						if (height > max_size) {
							width *= max_size / height;
							height = max_size;
						}
					}
					canvas.width = width;
					canvas.height = height;
					canvas.getContext('2d').drawImage(image, 0, 0, width, height);
					var dataUrl = canvas.toDataURL('image/jpeg');
					//var dataUrl = canvas.toDataURL('image/jpeg', 0.90);	// 이미지 퀄리티 조절도 가능...
					var resizedImage = dataURLToBlob(dataUrl);	// 이미지를 바이너리 형태로 변환?
					
					// 이미지가 리사이즈 되었으면 파일 업로드하는 메소드 호출
					$.event.trigger({
						type: "imageResized",
						blob: resizedImage,
						url: dataUrl
					});
					return false;
				}
				image.src = readerEvent.target.result;
			}
			reader.readAsDataURL(file);
		}
	}
	return false;
});

<file input을 통해 file을 선택했을 경우 동작하는 메소드>

 

// String to Binary 메소드 같은데 구글링으로 얻어온 것이라 자세한 내용은 모름 ㅎㅎ
var dataURLToBlob = function(dataURL) {
	var BASE64_MARKER = ';base64,';
	if (dataURL.indexOf(BASE64_MARKER) == -1) {
		var parts = dataURL.split(',');
		var contentType = parts[0].split(':')[1];
		var raw = parts[1];

		return new Blob([raw], {type: contentType});
	}

	var parts = dataURL.split(BASE64_MARKER);
	var contentType = parts[0].split(':')[1];
	var raw = window.atob(parts[1]);
	var rawLength = raw.length;

	var uInt8Array = new Uint8Array(rawLength);

	for (var i = 0; i < rawLength; ++i) {
		uInt8Array[i] = raw.charCodeAt(i);
	}

	return new Blob([uInt8Array], {type: contentType});
}

<String을 Binary로 변환해 주는 메소드. 구글링 결과물로 정확한 내용은 검토해 보지 못함>

 

 

$(document).on("imageResized", function (event) {
	var data = new FormData($("form[id*='_imageUploadForm']")[0]);
	if (event.blob && event.url) {
		// 리사이즈 된 이미지 첨부, 파일명은 실제 선택한 파일명을 넘겨 서버단에서 처리하도록...
		data.append('Filedata', event.blob);
		data.append('file_name', $("#_inputFile").prop('files')[0].name);

		$.ajax({
			url: "Action Url 입력",
			data: data,
			cache: false,
			contentType: false,
			processData: false,
			type: 'POST',
			success: cbUpload,
			error : function(err){
				alert("파일 업로드를 할 수 없습니다. 잠시 후 다시 시도해 주세요.");
			}
		});
	}
});

<리사이징 된 파일을 업로드 하는 메소드>

 

 

728x90
반응형