diff options
Diffstat (limited to 'files/ko/web/html/canvas/tutorial/compositing')
-rw-r--r-- | files/ko/web/html/canvas/tutorial/compositing/example/index.html | 293 | ||||
-rw-r--r-- | files/ko/web/html/canvas/tutorial/compositing/index.html | 106 |
2 files changed, 399 insertions, 0 deletions
diff --git a/files/ko/web/html/canvas/tutorial/compositing/example/index.html b/files/ko/web/html/canvas/tutorial/compositing/example/index.html new file mode 100644 index 0000000000..e3d74f5220 --- /dev/null +++ b/files/ko/web/html/canvas/tutorial/compositing/example/index.html @@ -0,0 +1,293 @@ +--- +title: 도형 합성 예제 +slug: Web/HTML/Canvas/Tutorial/Compositing/Example +tags: + - HTML5 + - 그래픽 + - 예제 + - 캔버스 +translation_of: Web/API/Canvas_API/Tutorial/Compositing/Example +--- +<div>{{CanvasSidebar}}</div> + +<p>이 샘플 프로그램에서는 여러 가지 <a href="/en-US/docs/Web/API/CanvasRenderingContext2D.globalCompositeOperation">도형 합성 방법</a>을 보여줍니다. 출력은 다음과 같습니다:</p> + +<p>{{ EmbedLiveSample('도형_합성_예제', '100%', '7250', '', 'Web/HTML/Canvas/Tutorial/Compositing/Example') }}</p> + +<h2 id="도형_합성_예제">도형 합성 예제</h2> + +<p>다음 코드에서는 프로그램의 나머지 부분에서 사용할 전역 값을 설정합니다.</p> + +<pre class="brush: js">var canvas1 = document.createElement("canvas"); +var canvas2 = document.createElement("canvas"); +var gco = [ 'source-over','source-in','source-out','source-atop', + 'destination-over','destination-in','destination-out','destination-atop', + 'lighter', 'copy','xor', 'multiply', 'screen', 'overlay', 'darken', + 'lighten', 'color-dodge', 'color-burn', 'hard-light', 'soft-light', + 'difference', 'exclusion', 'hue', 'saturation', 'color', 'luminosity' + ].reverse(); +var gcoText = [ +'기본 설정으로, 새로운 도형이 원래 도형 위에 그려집니다.', +'새로운 도형이 원래 도형과 겹치는 부분에만 그려지며, 나머지는 투명하게 설정됩니다.', +'새로운 도형이 원래 도형과 겹치지 않는 부분에만 그려집니다.', +'새로운 도형이 원래 도형과 겹치는 부분에만 그려집니다.', +'새로운 도형이 원래 도형 아래에 그려집니다.', +'원래 도형 중 새로운 도형과 겹치는 부분이 유지되며, 나머지는 투명하게 설정됩니다.', +'원래 도형 중 새로운 도형과 겹치지 않는 부분이 유지됩니다.', +'원래 도형 중 새로운 도형과 겹치는 부분만 유지됩니다. 새로운 도형은 원래 도형 아래에 그려집니다.', +'두 도형이 겹치는 곳의 색상이 두 색상값을 합한 값으로 결정됩니다.', +'새로운 도형만 그려집니다.', +'두 도형이 겹치는 곳이 투명하게 변하며, 나머지는 평범하게 그려집니다.', +'위쪽 레이어의 픽셀값이 아래쪽 레이어의 해당하는 픽셀값과 곱해지며, 결과적으로 어두운 이미지가 생성됩니다.', +'픽셀값을 뒤집고 곱한 다음 도로 뒤집습니다. 결과적으로 밝은 이미지가 생성됩니다(multiply의 반대).', +'multiply와 screen의 조합입니다. 아래쪽 레이어의 어두운 부분은 더 어두워지고, 밝은 부분은 더 밝아집니다.', +'두 레이어 중 어두운 픽셀값을 취합니다.', +'두 레이어 중 밝은 픽셀값을 취합니다.', +'아래쪽 레이어의 픽셀값을 위쪽 레이어의 뒤집힌 픽셀값으로 나눕니다.', +'아래쪽 레이어의 뒤집힌 픽셀값을 위쪽 레이어의 픽셀값으로 나누고, 그 값을 도로 뒤집습니다.', +'overlay와 같이 multiply와 screen의 조합이지만, 위아래 레이어의 순서가 바뀐 상태입니다.', +'조금 더 부드러운 hard-light입니다. 완전한 검은색/흰색에서 무조건 완전한 검은색/흰색이 나오지 않습니다.', +'한쪽 레이어의 픽셀값에서 다른 쪽 레이어의 픽셀값을 뺍니다. 빼는 순서는 결과값이 양수가 나오는 순서입니다.', +'difference와 비슷하지만 대비가 덜합니다.', +'아래쪽 레이어의 채도(chroma)와 명도(luma)를 보존하고 위쪽 레이어의 색상(hue)을 적용합니다.', +'아래쪽 레이어의 색상과 명도를 보존하고 위쪽 레이어의 채도를 적용합니다.', +'아래쪽 레이어의 명도를 보존하고 위쪽 레이어의 색상과 채도를 적용합니다.', +'아래쪽 레이어의 색상과 채도를 보존하고 위쪽 레이어의 명도를 적용합니다.' + ].reverse(); +var width = 320; +var height = 340; +</pre> + +<h3 id="메인_프로그램">메인 프로그램</h3> + +<p>페이지를 불러오고 나면 다음 코드에서 예제를 준비하고 실행합니다:</p> + +<pre class="brush: js">window.onload = function() { + // lum in sRGB + var lum = { + r: 0.33, + g: 0.33, + b: 0.33 + }; + // 캔버스 크기 변경 + canvas1.width = width; + canvas1.height = height; + canvas2.width = width; + canvas2.height = height; + lightMix() + colorSphere(); + runComposite(); + return; +}; +</pre> + +<p>또한 다음 코드의 <code>runComposite()</code>가 여러 가지 작업을 처리하며, 어려운 부분은 보조 함수를 사용합니다.</p> + +<pre class="brush: js">function createCanvas() { + var canvas = document.createElement("canvas"); + canvas.style.background = "url("+op_8x8.data+")"; + canvas.style.border = "1px solid #000"; + canvas.style.margin = "5px"; + canvas.width = width/2; + canvas.height = height/2; + return canvas; +} + +function runComposite() { + var dl = document.createElement("dl"); + document.body.appendChild(dl); + while(gco.length) { + var pop = gco.pop(); + var dt = document.createElement("dt"); + dt.textContent = pop; + dl.appendChild(dt); + var dd = document.createElement("dd"); + var p = document.createElement("p"); + p.textContent = gcoText.pop(); + dd.appendChild(p); + + var canvasToDrawOn = createCanvas(); + var canvasToDrawFrom = createCanvas(); + var canvasToDrawResult = createCanvas(); + + var ctx = canvasToDrawResult.getContext('2d'); + ctx.clearRect(0, 0, width, height) + ctx.save(); + ctx.drawImage(canvas1, 0, 0, width/2, height/2); + ctx.globalCompositeOperation = pop; + ctx.drawImage(canvas2, 0, 0, width/2, height/2); + ctx.globalCompositeOperation = "source-over"; + ctx.fillStyle = "rgba(0,0,0,0.8)"; + ctx.fillRect(0, height/2 - 20, width/2, 20); + ctx.fillStyle = "#FFF"; + ctx.font = "14px arial"; + ctx.fillText(pop, 5, height/2 - 5); + ctx.restore(); + + var ctx = canvasToDrawOn.getContext('2d'); + ctx.clearRect(0, 0, width, height) + ctx.save(); + ctx.drawImage(canvas1, 0, 0, width/2, height/2); + ctx.fillStyle = "rgba(0,0,0,0.8)"; + ctx.fillRect(0, height/2 - 20, width/2, 20); + ctx.fillStyle = "#FFF"; + ctx.font = "14px arial"; + ctx.fillText('기존 도형', 5, height/2 - 5); + ctx.restore(); + + var ctx = canvasToDrawFrom.getContext('2d'); + ctx.clearRect(0, 0, width, height) + ctx.save(); + ctx.drawImage(canvas2, 0, 0, width/2, height/2); + ctx.fillStyle = "rgba(0,0,0,0.8)"; + ctx.fillRect(0, height/2 - 20, width/2, 20); + ctx.fillStyle = "#FFF"; + ctx.font = "14px arial"; + ctx.fillText('새로운 도형', 5, height/2 - 5); + ctx.restore(); + + dd.appendChild(canvasToDrawOn); + dd.appendChild(canvasToDrawFrom); + dd.appendChild(canvasToDrawResult); + + dl.appendChild(dd); + } +}; +</pre> + +<h3 id="보조_함수">보조 함수</h3> + +<p>이 프로그램에서는 몇몇 보조 함수를 사용합니다.</p> + +<pre class="brush: js">var lightMix = function() { + var ctx = canvas2.getContext("2d"); + ctx.save(); + ctx.globalCompositeOperation = "lighter"; + ctx.beginPath(); + ctx.fillStyle = "rgba(255,0,0,1)"; + ctx.arc(100, 200, 100, Math.PI*2, 0, false); + ctx.fill() + ctx.beginPath(); + ctx.fillStyle = "rgba(0,0,255,1)"; + ctx.arc(220, 200, 100, Math.PI*2, 0, false); + ctx.fill() + ctx.beginPath(); + ctx.fillStyle = "rgba(0,255,0,1)"; + ctx.arc(160, 100, 100, Math.PI*2, 0, false); + ctx.fill(); + ctx.restore(); + ctx.beginPath(); + ctx.fillStyle = "#f00"; + ctx.fillRect(0,0,30,30) + ctx.fill(); +}; +</pre> + +<pre class="brush: js">var colorSphere = function(element) { + var ctx = canvas1.getContext("2d"); + var width = 360; + var halfWidth = width / 2; + var rotate = (1 / 360) * Math.PI * 2; // per degree + var offset = 0; // scrollbar offset + var oleft = -20; + var otop = -20; + for (var n = 0; n <= 359; n ++) { + var gradient = ctx.createLinearGradient(oleft + halfWidth, otop, oleft + halfWidth, otop + halfWidth); + var color = Color.HSV_RGB({ H: (n + 300) % 360, S: 100, V: 100 }); + gradient.addColorStop(0, "rgba(0,0,0,0)"); + gradient.addColorStop(0.7, "rgba("+color.R+","+color.G+","+color.B+",1)"); + gradient.addColorStop(1, "rgba(255,255,255,1)"); + ctx.beginPath(); + ctx.moveTo(oleft + halfWidth, otop); + ctx.lineTo(oleft + halfWidth, otop + halfWidth); + ctx.lineTo(oleft + halfWidth + 6, otop); + ctx.fillStyle = gradient; + ctx.fill(); + ctx.translate(oleft + halfWidth, otop + halfWidth); + ctx.rotate(rotate); + ctx.translate(-(oleft + halfWidth), -(otop + halfWidth)); + } + ctx.beginPath(); + ctx.fillStyle = "#00f"; + ctx.fillRect(15,15,30,30) + ctx.fill(); + return ctx.canvas; +}; +</pre> + +<pre class="brush: js">// HSV (1978) = H: Hue / S: Saturation / V: Value +Color = {}; +Color.HSV_RGB = function (o) { + var H = o.H / 360, + S = o.S / 100, + V = o.V / 100, + R, G, B; + var A, B, C, D; + if (S == 0) { + R = G = B = Math.round(V * 255); + } else { + if (H >= 1) H = 0; + H = 6 * H; + D = H - Math.floor(H); + A = Math.round(255 * V * (1 - S)); + B = Math.round(255 * V * (1 - (S * D))); + C = Math.round(255 * V * (1 - (S * (1 - D)))); + V = Math.round(255 * V); + switch (Math.floor(H)) { + case 0: + R = V; + G = C; + B = A; + break; + case 1: + R = B; + G = V; + B = A; + break; + case 2: + R = A; + G = V; + B = C; + break; + case 3: + R = A; + G = B; + B = V; + break; + case 4: + R = C; + G = A; + B = V; + break; + case 5: + R = V; + G = A; + B = B; + break; + } + } + return { + R: R, + G: G, + B: B + }; +}; + +var createInterlace = function (size, color1, color2) { + var proto = document.createElement("canvas").getContext("2d"); + proto.canvas.width = size * 2; + proto.canvas.height = size * 2; + proto.fillStyle = color1; // top-left + proto.fillRect(0, 0, size, size); + proto.fillStyle = color2; // top-right + proto.fillRect(size, 0, size, size); + proto.fillStyle = color2; // bottom-left + proto.fillRect(0, size, size, size); + proto.fillStyle = color1; // bottom-right + proto.fillRect(size, size, size, size); + var pattern = proto.createPattern(proto.canvas, "repeat"); + pattern.data = proto.canvas.toDataURL(); + return pattern; +}; + +var op_8x8 = createInterlace(8, "#FFF", "#eee");</pre> diff --git a/files/ko/web/html/canvas/tutorial/compositing/index.html b/files/ko/web/html/canvas/tutorial/compositing/index.html new file mode 100644 index 0000000000..108c493d9d --- /dev/null +++ b/files/ko/web/html/canvas/tutorial/compositing/index.html @@ -0,0 +1,106 @@ +--- +title: 도형 합성 +slug: Web/HTML/Canvas/Tutorial/Compositing +tags: + - HTML5 + - 그래픽 + - 캔버스 +translation_of: Web/API/Canvas_API/Tutorial/Compositing +--- +<p>이전 페이지들에서 나온 모든 예제에서, 새로 그리는 도형은 언제나 이미 그려진 도형의 위에 그려졌습니다. 대부분의 상황에서는 이렇게 하는 것이 적절하지만, 도형을 합성하기 위한 순서를 제한하게 되는데, <code>globalCompositeOperation</code> 속성을 설정함으로써 이러한 상태를 바꿀 수 있습니다.</p> + +<h2 id="globalCompositeOperation" name="globalCompositeOperation"><code>globalCompositeOperation</code></h2> + +<p>기존 도형 뒤에 새로운 도형을 그릴 수 있을 뿐만 아니라, 도형의 일정 영역을 가려 보이지 않게 하거나 캔버스의 특정 부분을 지우는 (<code>clearRect()</code> 메소드는 사각형의 영역만을 지우지만, 이같은 제한도 없다.) 등의 효과를 얻을 수도 있습니다.</p> + +<dl> + <dt><code>globalCompositeOperation = <em>type</em></code></dt> + <dd>새로운 도형을 그릴 때, 도형 합성 방법을 설정합니다. type은 다음 26종류의 합성 방법 중에서 선택할 수 있습니다.</dd> +</dl> + +<p>다음 예제의 코드를 확인하려면 <a href="/ko/docs/Web/HTML/Canvas/Tutorial/Compositing/Example">도형 합성 예제</a>를 확인해 주세요.</p> + +<p>{{ EmbedLiveSample('도형_합성_예제', 750, 6750, '', 'Web/HTML/Canvas/Tutorial/Compositing/Example') }}</p> + +<h2 id="Clipping_paths" name="Clipping_paths">잘라내기 경로(Clipping path)</h2> + +<p><img alt="" class="internal" src="https://mdn.mozillademos.org/files/209/Canvas_clipping_path.png" style="float: right;"> 잘라내기 경로는 다른 캔버스 도형과 비슷하지만, 다른 도형에서 원하지 않는 부분을 가리는 가면과 같은 역할을 합니다. 오른쪽에 있는 그림을 보면 어떤 역할을 하는지 알 수 있을 것입니다. 붉은 별 모양이 잘라내기 경로입니다. 이 경로 밖에 있는 모든 것은 캔버스에 그려지지 않을 것입니다.</p> + +<p>잘라내기 경로와 위에서 살펴본 <code>globalCompositeOperation</code> 속성을 비교해 보면, <code>source-in</code>과 <code>source-atop</code>에서 비슷한 효과가 보입니다. 이들과 잘라내기 경로와의 가장 중요한 차이점은, 잘라내기 경로 자체는 캔버스에 전혀 그려지지 않는다는 것입니다. 잘라내기 경로는 제한된 영역 안에서 여러 가지 도형을 그리는 데에 적합합니다.</p> + +<p><a href="/en-US/docs/Web/Guide/HTML/Canvas_tutorial/Drawing_shapes#Drawing_paths" title="Web/Guide/HTML/Canvas_tutorial/Drawing_shapes#Drawing_paths">캔버스에 도형 그리기</a>에서는 <code>stroke()</code>과 <code>fill()</code> 메소드만을 설명했었는데, <code>clip()</code>이라는 세 번째 메소드도 있습니다.</p> + +<dl> + <dt><code>clip()</code></dt> + <dd>현재 그려지는 경로를 현재 잘라내기 경로로 만듭니다.</dd> +</dl> + +<p>경로를 닫기 위해 <code>closePath()</code> 대신 <code>clip()</code>을 사용하고, 경로를 채우거나 윤곽선을 만드는 대신 잘라내기 경로로 만들 수 있습니다.</p> + +<p>{{HTMLElement("canvas")}} 요소의 초기 설정값으로써, 캔버스는 캔버스와 똑같은 크기의 잘라내기 경로를 가집니다. 크기가 똑같기 때문에 잘라내기 효과는 나타나지 않습니다.</p> + +<h3 id="A_clip_example" name="A_clip_example"><code>clip</code> 예제</h3> + +<p>다음 예제에서는 특정 영역의 별들만 보이도록 동그란 모양의 잘라내기 경로를 사용할 것입니다.</p> + +<pre class="brush: js">function draw() { + var ctx = document.getElementById('canvas').getContext('2d'); + ctx.fillRect(0,0,150,150); + ctx.translate(75,75); + + // 동그란 모양의 잘라내기 경로를 생성한다 + ctx.beginPath(); + ctx.arc(0,0,60,0,Math.PI*2,true); + ctx.clip(); + + // 배경을 그린다 + var lingrad = ctx.createLinearGradient(0,-75,0,75); + lingrad.addColorStop(0, '#232256'); + lingrad.addColorStop(1, '#143778'); + + ctx.fillStyle = lingrad; + ctx.fillRect(-75,-75,150,150); + + // 별을 그린다 + for (var j=1;j<50;j++){ + ctx.save(); + ctx.fillStyle = '#fff'; + ctx.translate(75-Math.floor(Math.random()*150), + 75-Math.floor(Math.random()*150)); + drawStar(ctx,Math.floor(Math.random()*4)+2); + ctx.restore(); + } + +} + +function drawStar(ctx,r){ + ctx.save(); + ctx.beginPath() + ctx.moveTo(r,0); + for (var i=0;i<9;i++){ + ctx.rotate(Math.PI/5); + if(i%2 == 0) { + ctx.lineTo((r/0.525731)*0.200811,0); + } else { + ctx.lineTo(r,0); + } + } + ctx.closePath(); + ctx.fill(); + ctx.restore(); +} +</pre> + +<div class="hidden"> +<pre class="brush: html"><canvas id="canvas" width="150" height="150"></canvas></pre> + +<pre class="brush: js">draw();</pre> +</div> + +<p>코드의 위쪽 몇 줄에서는 배경으로 캔버스 크기와 같은 검은색 네모를 그리고, 가운데로 원점을 옮깁니다. 그런 다음 호를 그리고 <code>clip()</code>을 사용하여 동그란 모양의 잘라내기 경로를 생성합니다. 캔버스 상태를 저장할 때 잘라내기 경로도 같이 저장됩니다. 이전의 잘라내기 경로를 보존하려면, 새로운 잘라내기 경로를 만들기 전에 캔버스 상태를 저장하면 됩니다.</p> + +<p>잘라내기 경로를 만든 후에 그려지는 모든 것들은, 그 경로의 안쪽에서만 보입니다. 이는 그 다음에 그려지는 선형 그라디언트에서 확실히 볼 수 있습니다. 이렇게 하고 나서, <code>drawStar()</code> 함수를 사용하여 위치와 크기가 모두 다른 50개의 별을 그립니다. 이 별들은 잘라내기 경로 안쪽에만 나타납니다.</p> + +<p>{{EmbedLiveSample("A_clip_example", "180", "180", "https://mdn.mozillademos.org/files/208/Canvas_clip.png")}}</p> + +<p>{{PreviousNext("Web/Guide/HTML/Canvas_tutorial/Transformations", "Web/Guide/HTML/Canvas_tutorial/Basic_animations")}}</p> |