본문 바로가기

HTML5/Image Split

HTML5 Image Split example

HTML5 이미지 자르기 ( HTML5 Image Splitting example )


캔바스에 그려진 이미지를 일정 크기로 잘라서 다수개의 ImageData 오브젝트를 생성하고 화면에 출력하는 예제

<!DOCTYPE html>
<html>
<head>
<meta charset="EUC-KR">
<title>이미지 조각 맞추기 예제</title>
<script type="text/javascript" src="jquery-2.1.1.min.js"></script>
<script type="text/javascript">

var canvas = null;
var ctx = null;
var imgObj = null;
var beginX=0, beginY=0; 	// 이미지가 그려지는 캔바스상의 시작좌표
var fragmentArr = new Array();
var prevFragObj = null;
var currFragObj = null;
var clickedFrag = null;		//ImageFragment Object
var clickedGrid = null;		//Rect Object

$(document).ready(function() {
	
	canvas = document.getElementById( "canvas1" );
    ctx = canvas.getContext( "2d" );


	$('#btnShow').click(function(){
		imgObj = new Image();
		imgObj.onload=function(e){
			drawImg(imgObj);
			drawGrid(imgObj,'white');
		};
		imgObj.src='sample.jpg';
	});
	
	$('#btnSplit').click(function(){
		splitImage(imgObj);
	});
	
	$('#canvas1').on('mousemove',function(e){
		var mx = e.pageX-canvas.offsetLeft;
		var my = e.pageY-canvas.offsetTop;
		
		for(var i=0;i<fragmentArr.length;i++) {
			if(fragmentArr[i].fragmentPos.isIntersect(mx,my)) {
				//console.log('배열['i+'] 위에 마우스 위치함');
				if(prevFragObj==null) {
					drawRectOnFrag(fragmentArr[i], 'blue');
					prevFragObj = fragmentArr[i];
					return;
				}else if(prevFragObj==fragmentArr[i]) {
					return;
				}else {
					drawRectOnFrag(prevFragObj, 'white');
					drawRectOnFrag(fragmentArr[i], 'blue');
					prevFragObj = fragmentArr[i];
				}
				return;
			}
		}
	});
	
	$('#canvas1').on('mousedown', function(e){
		//원본 이미지 영역을 클릭했는지, 이미지 조각이 그려지는 영역을 클릭했는지 구분한다
		var mx = e.pageX-canvas.offsetLeft;
		var my = e.pageY-canvas.offsetTop;
		//원본 이미지 영역에서 클릭한 것인가?
		if(isIntersect(beginX, beginY, imgObj.width, imgObj.height, mx, my)){
			//alert('원본 이미지 영역 클릭');
			for(var i=0;i<fragmentArr.length;i++) {
				if(fragmentArr[i].originPos.isIntersect(mx,my)) {
					//alert(i+' dest 영역 클릭함');
					clickedGrid = fragmentArr[i].originPos;
					//이미지 조각을 원본 이미지 영역의 클릭된 그리드 안에 그림
					if(clickedFrag) {
						ctx.putImageData(clickedFrag.imgData, clickedGrid.x, clickedGrid.y);

						ctx.fillStyle = 'white';
						ctx.rect(clickedFrag.x, clickedFrag.y, Rect.w, Rect.h);
						ctx.fill();
						clickedFrag = null;
					}
					return;
				}
			}
			return;
		}else { // 조각 이미지를 클릭했는지 확인한다
			for(var i=0;i<fragmentArr.length;i++) {
				if(fragmentArr[i].fragmentPos.isIntersect(mx,my)) {
					//alert('이미지 조각을 클릭함');
					clickedFrag = fragmentArr[i];
					return;
				}
			}
		}
		//조각 이미지 영역에서 클릭된 이미지 조각 찾기
	});
}); // end of ready();

//캔바스 중앙에 원본 이미지를 그린다
function drawImg(imgObj) {
	beginX = (canvas.width-imgObj.width)/2;
	beginY = (canvas.height-imgObj.height)/2;
	
	ctx.drawImage(imgObj,beginX,beginY);
}

//화면상의 이미지가 있는 위치에 6x5 개(총 30개)의 그리드를 그린다
function drawGrid(imgObj,color) {
	var gridW = imgObj.width/6;
	var gridH = imgObj.height/5;
	for(var i=0;i<=5;i++) { //가로선 그리기
		ctx.beginPath();
		ctx.strokeStyle=color;
		ctx.moveTo(beginX, beginY+(gridH*i));
		ctx.lineTo(beginX+imgObj.width, beginY+(gridH*i));
		ctx.stroke();
	}
	for(var i=0;i<=6;i++) { //세로선 그리기
		ctx.beginPath();
		ctx.strokeStyle=color;
		ctx.moveTo(beginX+(gridW*i), beginY);
		ctx.lineTo(beginX+(gridW*i), beginY+imgObj.height);
		ctx.stroke();
	}
}

//원본 이미지를 6x5 개로 잘라서 배열에 저장하고, 배열저장 순서를 무작위로 섞고,
// 캔바스 중앙에 그려진 원본 이미지를 삭제하고 그 자리에 6x5개의 그리드를 그리고,
// 캔바스 좌우상하 가장자리에 배열에 저장된 모든 조각 이미지를 그린다
function splitImage(imgObj){
	
	var w = imgObj.width;
	var h = imgObj.height;
	
	var tilesX = 6
    var tilesY = 5
    var tileWidth = w/tilesX;
	var tileHeight = h/tilesY;
    
	Rect.w = tileWidth;
	Rect.h = tileHeight;
	
    var totalTiles = tilesX * tilesY;        
    var tileData = new Array();
    //var fragmentArr = new Array(); // ImageFrament 객체를 저장할 배열
    
    //이미지 조각을 배열에 저장
    for(var i=0; i<tilesY; i++) 	//행
    {
      for(var j=0; j<tilesX; j++)	//열
      {
    	var originRect = new Rect(j*tileWidth+beginX, i*tileHeight+beginY);
		var imgFragData = ctx.getImageData(originRect.x, originRect.y, Rect.w, Rect.h);
		var imgFragObj = new ImageFragment(imgFragData, originRect);
        fragmentArr.push(imgFragObj);
      }
    }
    //이미지 조각 순서 섞기
    fragmentArr = shuffle(fragmentArr);
    
    //원본 이미지 지우기
    ctx.clearRect(0,0,canvas.width, canvas.height);
    
    //원본 이미지가 사라진 위치에 그리드 그리기
    drawGrid(imgObj,'blue');
    
    //이미지 조각을 캔바스 상하좌우에 배치하기
    var topRight=true;
    var topDownIdx = 0;
    var leftRightIdx = 0;
    
    for(var i=0; i<fragmentArr.length; i++)
    {
    	//캔바스 상단/하단에 이미지 조각 배치하기
    	if(topRight){
	    	if(i*tileWidth<=(canvas.width-tileWidth)){
	    		fragmentArr[i].fragmentPos = new Rect(i*tileWidth, 0),
	    		ctx.putImageData(fragmentArr[i].imgData, i*tileWidth, 0);
	    	}else if((leftRightIdx * tileWidth)<= (canvas.width-tileWidth)){
	    		fragmentArr[i].fragmentPos = new Rect(leftRightIdx * tileWidth, canvas.height-tileHeight),
	    		ctx.putImageData(fragmentArr[i].imgData, leftRightIdx++ * tileWidth, canvas.height-tileHeight);
	    	}else {
	    		topRight = false
	    		i--;
	    	}
    	}else{//캔바스 좌우 양단에 이미지 조각 배치하기
    		if(topDownIdx*tileHeight<=(canvas.height-tileHeight*2)){
    			fragmentArr[i].fragmentPos = new Rect(0, tileHeight+tileHeight*topDownIdx);
	    		ctx.putImageData(fragmentArr[i].imgData, 0, tileHeight+tileHeight*topDownIdx);//왼쪽에 그림
	    		++i;
	    		fragmentArr[i].fragmentPos = new Rect(canvas.width-tileWidth, tileHeight+tileHeight*topDownIdx);
	    		ctx.putImageData(fragmentArr[i].imgData, canvas.width-tileWidth, tileHeight+tileHeight*topDownIdx);//오른쪽에 그림
	    		topDownIdx++;
	    	}
    	}
    }
}

function shuffle(fragmentArr) {
	
	var resultArr = new Array();
	var idx = 0;
	
	while(fragmentArr.length>0) {
		var idx = Math.floor(Math.random() * fragmentArr.length);
		var fragObj = fragmentArr[idx];
		fragmentArr.splice(idx,1);
		resultArr.push(fragObj);
		//console.log(idx+','+tileData.length);
	}
	return resultArr;
	
}

function ImageFragment(imgData, originPos) {

	this.imgData = imgData;				//이미지 조각의 이미지 데이터(ImageData)
	this.originPos = originPos; 		//소스 이미지 상의 위치(Rect)
	this.fragmentPos = null;		//이미지 조각이 그려지는 위치(Rect)
}

//조각 이미지의 위치와 크기를 표현
function Rect(x,y) {
	var w = w;
	var h = h;
	
	this.x = x;
	this.y = y;

	this.isIntersect = function(x,y) {
		if(isIntersect(this.x, this.y, Rect.w, Rect.h, x, y)) {
			return true;
		}
		else {
			return false;
		}
	}
}

function isIntersect(x1,y1,w1,h1, x2,y2) {
	if((x2>x1 && x2<x1+w1) && (y2>y1 && y2<y1+h1)) {
		return true;
	}
	else {
		return false;
	}
}

//조각 이미지의 테두리를 청색 혹은 백색으로 그린다
function drawRectOnFrag(imgFragObj,color) {

	var x = imgFragObj.fragmentPos.x;
	var y = imgFragObj.fragmentPos.y;
	var w = Rect.w;
	var h = Rect.h;
	
	ctx.beginPath();
	ctx.rect(x, y, w, h);

    ctx.lineWidth = 1;
    ctx.strokeStyle = color;
    ctx.stroke();
}
</script>
<style type="text/css">
	canvas {border:1px solid black; }
</style>
</head>
<body>
<canvas id="canvas1" width="950" height="700">
</canvas>
<button id="btnShow">그림보기</button>
<button id="btnSplit">조각내기</button>
</body>
</html>