HTML5 캔바스 상의 이미지를 서버로 업로드하는 예
웹브라우저의 Canvas 에 그려진 이미지를 웹서버로 전달하여 이미지 파일로 저장하려고 한다.
canvas.toDataURL() 함수를 이용하여 Base64 문자열로 인코딩된 이미지 데이터를 구할 수 있으므로 일반 문자열처럼 쉽게 서버로 전송할 수 있다.
이미지 데이터가 Base64 문자열로 인코딩되면 문자열의 첫 부분은 'https://t1.daumcdn.net/cfile/tistory/221EF94756E6601616"txc-textbox" style="border: 1px solid rgb(203, 203, 203); padding: 10px; background-color: rgb(255, 255, 255);">
java.util.Base64
org.apache.commons.codec.binary.Base64
http://iharder.sourceforge.net/current/java/base64/
Canvas에 그려진 이미지를 Base64 문자열로 인코딩하여 jQuery.ajax() 를 이용하여 서버로 전송하는 클라이언트측 코드
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Image Capture and Submit</title> <script type="text/javascript" src="jquery-2.1.1.min.js"></script> <script type="text/javascript"> var imageObj = null; var mx,my,cmx,cmy = 0; var isDown = false; $(function() { $('#file-input').change(function(e) { var file = e.target.files[0], imageType = /image.*/; if (!file.type.match(imageType)) return; var reader = new FileReader(); reader.onload = fileOnload; reader.readAsDataURL(file); }); function fileOnload(e) { var $img = $('<img>', { src: e.target.result }); var canvas1 = $('#canvas1')[0]; var context = canvas1.getContext('2d'); $img.load(function() { context.drawImage(this, 0, 0); imageObj = this; }); } $('#canvas1').on('mousedown',function(e){ var element = this; var offsetX = 0; var offsetY = 0; if (element.offsetParent !== undefined) { do { offsetX += element.offsetLeft; offsetY += element.offsetTop; } while ((element = element.offsetParent)); mx = e.pageX - offsetX; my = e.pageY - offsetY; isDown = true; console.log(mx+','+my); } }); $('#canvas1').on('mousemove',function(e){ if(!isDown) return; var element = this; var offsetX = 0; var offsetY = 0; if (element.offsetParent !== undefined) { do { offsetX += element.offsetLeft; offsetY += element.offsetTop; } while ((element = element.offsetParent)); cmx = e.pageX - offsetX; cmy = e.pageY - offsetY; console.log(cmx+','+cmy); var canvas1 = $('#canvas1')[0]; var context = canvas1.getContext('2d'); context.drawImage(imageObj,0,0);//배경 이미지를 그린다 //마우스로 선택된 영역에 대시라인으로 사각형을 그린다 context.setLineDash([5]); context.strokeStyle = 'red'; context.strokeRect(mx,my,cmx-mx,cmy-my); } }); $('#canvas1').on('mouseup',function(e){ var canvas1 = $('#canvas1')[0]; var context = canvas1.getContext('2d'); context.drawImage(imageObj,0,0);//배경 이미지를 그린다 //마우스로 선택된 영역에 반투명 사각형을 그려서 선택영역을 표시해준다 context.fillStyle = 'rgba(30,0,0,0.1)'; context.fillRect(mx,my,cmx-mx,cmy-my); //마우스로 선택된 영역에 대시라인으로 사각형을 그린다 context.setLineDash([5]); context.strokeStyle = 'red'; context.strokeRect(mx,my,cmx-mx,cmy-my); isDown = false; }); $('#save').click(function(){ sendBase64Img(); }); $('#copy').click(function() { drawOnCanvas2(); }); }); function drawOnCanvas2() { var canvas2 = $('#canvas2')[0]; $(canvas2).attr('width', cmx-mx+'px'); $(canvas2).attr('height', cmy-my+'px'); var context = canvas2.getContext('2d'); context.clearRect(0,0,canvas2.width, canvas2.height); var sx = mx; var sy = my; var sw = cmx-mx; var sh = cmy-my; var dx = 0; var dy = 0; var dw = sw; var dh = sh; context.drawImage(imageObj, sx, sy, sw, sh, dx, dy, dw, dh); } function sendBase64Img() { var canvas2 = document.getElementById('canvas2'); var dataURL = canvas2.toDataURL();//이미지 데이터가 base64 문자열로 인코딩된 데이터 // base64문자열의 첫 부분에 위치한 'https://t1.daumcdn.net/cfile/tistory/24343B4956E6601629"");*/ $.ajax({ type: "POST", url: "saveBase64.jsp", contentType: "application/x-www-form-urlencoded; charset=utf-8", data: { "imgBase64": dataURL } }).success(function(o) { alert('선택영역을 서버의 이미지 파일에 저장했습니다'); }); } </script> </head> <body> <canvas id="canvas1" width="500px" height="300px"></canvas> <br> <input type="file" id="file-input"> <button id="copy">Copy Selection</button> <button id="save">Save to Server</button> <p> <canvas id="canvas2" width="500px" height="300px"></canvas> </body> </html>
서버측 코드 (jsp), Base64 인코딩 문자열을 수신하여 원래의 이미지 데이터로 디코딩하여 이미지 파일에 저장한다
<%@page import="test.base64.Base64"%> <%--@page import="org.apache.commons.codec.binary.Base64"--%> <%@page import="java.io.*"%> <%@page import="java.awt.image.*"%> <%@page import="javax.imageio.*"%> <%--@page import="java.util.Base64"--%> <%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%> <% request.setCharacterEncoding("utf-8"); String base64Str = request.getParameter("imgBase64"); //인코딩된 문자열의 처음에 위치한 'https://t1.daumcdn.net/cfile/tistory/2159EF4856E6601716",")+1, base64Str.length()); /* sourceforge에서 배포하는 Base64 클래스를 사용하면 가장 간단하게 디코딩과 이미지 파일에 저장을 동시에 처리한다*/ Base64.decodeToFile(base64Str, "d:/test/decodedImg.png"); //jpg,png ok /* java.util.Base64 클래스를 사용하여 디코딩한 후에 ImageIO를 이용하여 이미지 파일에 저장한다 byte[] decodedBytes = Base64.getDecoder().decode(base64Str); //java.util.Base64 try { BufferedImage bm = ImageIO.read(new ByteArrayInputStream(decodedBytes)); ImageIO.write(bm, "png", new File("d:/test/decodedImg.png")); } catch (IOException e) { e.printStackTrace(); } */ /* Apache Base64 클래스를 이용하여 디코딩한 후에 ImageIO를 이용하여 이미지 파일에 저장한다 byte[] decodedBytes = Base64.decodeBase64(base64Str); //apache Base64 try { BufferedImage bm = ImageIO.read(new ByteArrayInputStream(decodedBytes)); ImageIO.write(bm, "png", new File("d:/test/decodedImg.png")); } catch (IOException e) { e.printStackTrace(); } */ %>