상세 컨텐츠

본문 제목

html5 canvas 이미지 합성/ 이미지 겹치기 source-over source-atop 동해둘리의 실전 프로젝트 html canvas 시리즈 #2

IT공부방/HTML5, CSS

by 동해둘리 2019. 7. 2. 10:27

본문

반응형

동해둘리가 직접 개발했던 실전 프로젝트를 살펴보는 동해둘리의 실전프로젝트 2탄

 

지난 포스팅에서 html5 에서 제공하는 canvas를 이용하여 이미지를 합성하거나 이미지를 겹치는 방법을 살펴봤었습니다. 앱스토어에서 메리퀸 으로 검색하면 앱을 다운로드 받아서 실제 기능을 확인해 보실 수 있습니다

 

 

 

 

 

이번 포스팅에서는, 지난번에 이어서 실제 코드를 살펴보면서 html5 canvas를 이용한 이미지합성 / 이미지겹치기 에 대해 알아보도록 하겠습니다

 

html5 canvas

 

우선, 위 그림의 침대부분이 canvas 입니다. 그리고 이미지를 합성하기 위한 보이지 않는 hidden 속성의 canvas 가 두개 필요합니다. 

 

    <canvas style="z-index:5;position:relative; left:0px;" height="1215" width="1536" id="canvas_result">캔버스를 지원하지 않는 브라우저 입니다</canvas>

    <div style="z-inxex:50;visibility:hidden;position:absolute; left:0px;top:200px"><canvas height="1215" width="1536" id="canvas_for_compose">캔버스를 지원하지 않는 브라우저 입니다</canvas></div>

    <div style="z-inxex:30;visibility:hidden;position:absolute;left:0px;top:200px" id = "composed_image_div" width = 0 height = 0></div>

 

 

캔버스의 css 설정은 다음과 같습니다. 폭이 1536px, 높이가 1215px 인데요, 캔버스에 올라갈 이미지의 크기도 동일해야 합니다. 

 

<style type="text/css">

    #canvas_result{

        width:1536px; height:1215px; background-color:#ffffff;  

        position: relative; z-index: 1000; display: table;

        -moz-transform-origin: top left;

        -webkit-transform-origin: top left;

        -ms-transform-origin: top left;

        transform-origin: top left;

    }

</style>

 

 

 

 

캔버스에는 기본적으로 패턴이미지가 올라가지 않은 흰색 침구 사진을 먼저 올려놓습니다. 

 

html5 캔버스 이미지합성

 

 

캔버스에 이미지를 올려놓는 방법은 아래와 같이 몇줄의 코드로 가능합니다. 다만, 캔버스에 이미지를 그릴때 옵션을 주어 교집합/합집합 등의 이미지 합성을 하게 되는 것입니다. 

 

<!-- 위 그림에 있는 흰색 침대사진 이미지, 이미지 자체는 width 를 0으로 하여 안보이게 합니다 -->

<img id = "stitch_batang" src = "./pattern/stitch_batang.jpg" width = 0>

 

<script language = "javascript">

  // 위의 흰색 침대사진이 세팅된 img 객체를 불러옵니다. 

  var obBatangImg = document.getElementById("stitch_batang");

 

  // 앞서 준비해둔 canvas 객체를 불러옵니다. 

  const canvas_result = document.getElementById('canvas_result');

 

  // canvas 에 그림을 그리기위한 2d context 를 얻어옵니다

  // 2d context 는 canvas에 그리거나 이미지를 넣거나 할 때 사용하는 객체/ 메소드/ 속성등을 제공합니다.

  const ctx_result = canvas_result.getContext('2d');

 

  // drawImage 함수로 이미지를 canvas에 넣습니다

  ctx_result.drawImage(obBatangImg, 0, 0);        

 

 

  // 패턴이미지 선택시 사용하게될 canvas 와 canvas 의 2D context 객체를 전역변수에 세팅해둡니다.

  const canvas_for_compose = document.getElementById('canvas_for_compose');

  const ctx = canvas_for_compose.getContext('2d');

            

  gObResultCtx = ctx_result;            

  gObCanvasResult = canvas_result;

  gObCanvasForCompose = canvas_for_compose;

  gObCanvasForComposeCtx = ctx;                       

 

</script>

 

여기까지 하면 아래와 같이 비어있던 캔버스에 침대 이미지가 올라가게 됩니다.

 

 

 

 

canvas image duplicate/ editing

 

 

 

 

 

다음은 아래 빨간색 동그라미 부분의 패턴 이미지를 클릭했을 경우, 해당 패턴 이미지를 이불에 덮어씌우는 코드를 살펴보도록 하겠습니다. 

 

 

 

html5 canvas image example

 

 

 

패턴이미지를 클릭하게 되면 이불/이불윗단/앞베개/뒷베개/패드/매트리스커버 등의 각 위치에 해당 패턴이 씌워지게 되는데요, 위 그림에서 보듯이 기본은 '이불'로 세팅이 되어있습니다.

 

현재 선택된 침구의 위치(이불/베개/패드 등등)를 저장하기 위해서 hidden 속성의 input 태그를 사용했습니다

 

<input type = "hidden" size = 20 id = "select_position" style="width:200px" value = "이불">

 

var gObResultCtx = ""; // 결과가 보여질 canvas 의 2D context

var gObCanvasForComposeCtx = ""; //  합성을 위한 canvas 의 2D context 

 

var gDuvetPatternId = ""; // 현재 선택된 이불 패턴아이디

var gDuvetPatternImgUrl = ""; // 현재 선택된 이불 패턴이미지URL

 

// 패턴이미지를 클릭하면 실행되는 함수입니다

// sPatternBtnId 는 선택된 패턴을 기억하기 위해 인자로 받습니다

// sPatternImageURL 은 선택된 패턴 이미지를 canvas에 적용하기 위해 인자로 받습니다. 

 

function composeImage(sPatternBtnId, sPatternImageURL) {

 

     // 현재 선택된 침구의 위치(이불/베개/패드 등)를 읽어옵니다. 

     var obSelectPosition = document.getElementById("select_position");

 

      const item = new Image(); // 합성을 위한 침구의 각 위치별 이미지를 담게 될 객체

      const pattern = new Image(); // 합성될 패턴이미지를 위한 객체 

 

     // 현재 선택된 침구의 위치가 이불일 경우

     // 선택된 패턴ID와 이미지URL 을 저장해 두는 이유는 

     // 침구의 형태가 스티치/프릴/보더 등으로 변경되었을 경우에도

     // 기존에 선택된 패턴이미지를 기억했다가 자동으로 세팅하기 위함입니다. 

 

     if ( obSelectPosition.value == "이불" ) {             

         gDuvetPatternId = sPatternBtnId; // 전역변수에 현재 선택된 이불 패턴의 아이디를 저장합니다.

         gDuvetPatternImgUrl = sPatternImageURL; // 전역변수에 현재 선택된 이불 패턴의 이미지URL을 저장합니다

 

         // 윗부분에서 생성한 이미지 객체에 패턴이미지와 위치이미지를 적용합니다.

         item.src = "./pattern/stitch_duvet.png"; // 패턴과 합성하기위해 이불부분만 남아있는 이미지(아래에 사진참고)

         pattern.src = sPatternImageURL; // 선택된 패턴이미지URL

         

         item.onload = function () // 위치 이미지가 로드되면

         {

             pattern.onload = function () // 패턴이미지가 로드되면

             {

                    // 캔버스를 clear 시킵니다

                    gObCanvasForComposeCtx.clearRect(0,0,1536,1215); 

                   

                    // 겹치기 모드로 변환합니다.

                    gObCanvasForComposeCtx.globalCompositeOperation = "source-over"; 

 

                    // 선택된 침구의 위치에 해당하는 이미지를 캔버스에 그립니다.

                    gObCanvasForComposeCtx.drawImage(item, 0, 0); 

 

                    // 겹쳐지는 부분만 남고 안겹치는 부분은 투명하게 바뀌는 atop 모드로 전환합니다. 

                    gObCanvasForComposeCtx.globalCompositeOperation = "source-atop";

 

                   // 부드럽게 잘라내기 위해 alpha 값을 조금 낮춰줍니다

                    gObCanvasForComposeCtx.globalAlpha = .85;

 

                    // pattern 에 저장된 패턴이미지를 item 에 저장된 위치이미지와 합성합니다.

                    // 패턴이미지는 위치이미지보다 작기 때문에 반복적으로 이어져서 그려지도록

                    // createPattern 함수를 이용합니다. 

                    const pattern_ = gObCanvasForComposeCtx.createPattern(pattern, 'repeat');

                    // 캔버스 크기에 맞게 합성된 이미지를 채웁니다

                    gObCanvasForComposeCtx.rect(0, 0, 1536, 1215);

                    gObCanvasForComposeCtx.fillStyle = pattern_;

                    gObCanvasForComposeCtx.fill();

 

                    // 패턴합성용 캔버스에 있는 패턴이미지를 IMG 엘리먼트로 변경

                    var data = canvas_for_compose.toDataURL('image/png');               

 

                    var ComposedImage = document.createElement('IMG');

                    ComposedImage.src = data;                   

                    ComposedImage.id = "composed_image_id";

                    ComposedImage.width = 100;              

 

                    // 합성된 결과이미지를 저장할 div에 합성결과 이미지를 넣는다

                    document.getElementById('composed_image_div').appendChild(ComposedImage);       

 

                    var obComposedImg = document.getElementById("composed_image_id");

 

                    // 합성결과 이미지객체가 생성완료되었으면 결과가 보여지는 canvas에 넣는다 

                    obComposedImg.onload = function ()

                    {                       

                        gObResultCtx.globalAlpha = 1;

                        gObResultCtx.drawImage(obComposedImg, 0, 0);

 

                        // 선택된 침구의 위치에 해당하는 이미지(예를들어 이불)의 굴곡 및 그라데이션이 

                        // 패턴이미지를 덮어씌운 후에도 보이게 하기위해 alpha 값은 조듬 낮춰줍니다.

                        gObResultCtx.globalAlpha = .15;

                        gObResultCtx.drawImage(item, 0, 0);

                    }

             }

         }

     }

}

 

 

 

 

침구의 위치에 따라 침구의 형태에 따라 서로 다른 이미지를 사용해야하기 때문에, 전체 코드는 더 복잡하고 길어질 수 밖에 없는데요, 이불 부분만 합성되는 과정을 적어보았습니다.

 

 

실전프로젝트 라고 하지만, 합성되는 방법이 Alpha 값을 이용하기 때문에  패턴이미지가 완벽하게 선명한 형태로 씌워지지 않습니다. 아울러, 스트라이프(줄무니)패턴의 경우 침구의 굴곡에 따라 움직이지 않기 때문에 개선의 여지가 있습니다.

 

 

현재, 본 프로젝트는 와이어프레임을 적용한 침구의 모든 굴곡까지 표현하는 형태로 업그레이드 진행중입니다.

 

 

 

반응형

관련글 더보기

댓글 영역