정보
요청한 주제가 아래에 표시됩니다. 그러나 이 주제는 이 라이브러리에 포함되지 않습니다.

SVG 필터를 사용하여 두 개의 래스터 이미지를 블렌딩하는 방법

Internet Explorer 10부터는 <feImage><feBlend> SVG 필터 primitive를 사용하여 두 개의 래스터 이미지를 블렌딩하거나 병합할 수 있습니다. 지금부터 방법을 보여 드리려고 합니다.

수수께끼로 시작해 보겠습니다. slide1.jpg와 slide2.jpg의 블렌딩을 시도하는 다음 예제를 자세히 보세요.

예제 1


<!DOCTYPE html>
<html>

<head>
  <meta http-equiv="X-UA-Compatible" content="IE=10" >
  <meta content="text/html; charset=utf-8" http-equiv="Content-Type">
  <title>Example 1</title>
</head>

<body>
  <h1>Note that this example requires a browser that supports SVG filters, 
      such as Internet Explorer 10 or later.</h1>
  <svg>
    <defs>
      <filter id="myFilter">
        <feImage xlink:href="slide2.jpg" result="slide2" />
        <feBlend in="SourceGraphic" in2="slide2" mode="lighten" />
      </filter>
    </defs>   
    <image href="slide1.jpg" filter="url(#myFilter)" /> 
  </svg>
</body>

</html>

이 스크린샷은 예제 1의 예기치 않은 출력을 나타냅니다.

코드 예제에 설명된 대로 메시지를 보여 주는 예제 1 스크린샷

블렌딩된 이미지가 렌더링되지 않으므로 뭔가 잘못되었음을 알 수 있습니다. 무엇이 잘못되었는지 설명하기 전에 먼저 이 예제가 근본적으로 어떻게 작동하는지에 대해 설명하겠습니다.

예제 1은 myFilter SVG 필터를 slide1.jpg SVG 이미지 요소에 적용하여 slide1.jpg와 slide2.jpg를 블렌딩합니다.


<image xlink:href="slide1.jpg" filter="url(#myFilter)" />

myFilter SVG 필터는 두 개의 필터 primitive로 구성됩니다.


<feImage xlink:href="slide2.jpg" result="slide2" />
<feBlend in="SourceGraphic" in2="slide2" mode="lighten" />

<feImage>의 입력은 slide2.jpg이고 출력은 slide2입니다. slide2 모니커는 이제 다른 필터(예: (<feBlend>)에 대한 입력으로 사용할 수 있습니다.

<feBlend>는 두 개의 개체를 블렌딩하므로 inin2이라는 두 개의 입력을 갖습니다. 첫 번째 입력 in="SourceGraphic"은 필터가 적용되는 개체와 연관된 이미지를 나타냅니다. 즉, in="SourceGraphic"<image xlink:href="slide1.jpg" filter="url(#myFilter)" />에서 slide1.jpg를 나타냅니다.

이렇게 본질을 이해함으로써 왜 블렌딩된 이미지가 렌더링되지 않는지 답할 수 있습니다. SVG <image> 요소의 기본 widthheight0이기 때문입니다. 예제 1에서 <image> , widthheight 값을 지정하지 않았으므로 0이 기본값으로 사용되었습니다. 이로 인해 블렌딩된 이미지가 렌더링되지 않았습니다.

확실한 해결 방법은 <image> 요소에 대해 widthheight 값을 지정하는 것입니다(HTML의 <img> 요소와 혼동하지 마세요). slide1.jpg와 slide2.jpg의 정확한 크기를 알 수 없으므로 우선 다음과 같이 width="100%"height="100%"을 사용하여 시도해 보겠습니다.

예제 2


<!DOCTYPE html>
<html>

<head>
  <meta http-equiv="X-UA-Compatible" content="IE=10" >
  <meta content="text/html; charset=utf-8" http-equiv="Content-Type">
  <title>Example 2</title>
</head>

<body>
  <h1>Note that this example requires a browser that supports SVG filters, 
      such as Internet Explorer 10 or later.</h1>
  <svg>
    <defs>
      <filter id="myFilter">
        <feImage xlink:href="slide2.jpg" result="slide2" />
        <feBlend in="SourceGraphic" in2="slide2" mode="lighten" />
      </filter>
    </defs>   
    <image href="slide1.jpg" filter="url(#myFilter)" width="100%" height="100%" /> 
  </svg>
</body>

</html>

widthheight가 지정되면 블렌딩된 이미지가 렌더링됩니다(mode="lighten" 사용).

SVG 필터 메시지와 블렌딩된 이미지를 보여 주는 예제 2 스크린샷

분명히 뭔가 이상한 일이 아직 일어나고 있습니다. 한 가지 문제는 렌더링된 이미지가 예상보다 훨씬 작게 표시된다는 점입니다. 이 가정을 테스트하기 위해 블렌딩된 이미지를 먼저 표시하고(<image> 사용) 기본 이미지 slide1.jpg와 slide2.jpg를 나중에 표시합니다(<img> 사용).

예제 3


<!DOCTYPE html>
<html>

<head>
  <meta http-equiv="X-UA-Compatible" content="IE=10" >
  <meta content="text/html; charset=utf-8" http-equiv="Content-Type">
  <title>Example 3</title>
  <style>
    svg, img {
      display: block;
    }
    
    svg {
      border: 2px red solid;
    }
    
    img {
      border: 2px green solid;
    }    
  </style>
</head>

<body>
  <h1>Note that this example requires a browser that supports SVG filters, 
      such as Internet Explorer 10 or later.</h1>
  <svg>
    <defs>
      <filter id="myFilter">
        <feImage xlink:href="slide2.jpg" result="slide2" />
        <feBlend in="SourceGraphic" in2="slide2" mode="lighten" />
      </filter>
    </defs>   
    <image href="slide1.jpg" filter="url(#myFilter)" width="100%" height="100%" /> 
  </svg>
  <img src="slide1.jpg" />
  <img src="slide2.jpg" />
</body>

</html>

예제 3의 출력은 다음과 같습니다.

코드 예제의 출력을 보여 주는 예제 3 스크린샷

앞서 세운 가정이 맞았습니다. —100%widthheight의 값이 있음에도 불구하고 블렌딩된 이미지가 기본 이미지보다 작습니다.


<image href="slide1.jpg" filter="url(#myFilter)" width="100%" height="100%" />

이제 그 이유를 알아보겠습니다.

  • HTML에서 <img src="slide1.jpg" width="100%" height="100%">는 HTML 이미지를 전체 크기로 렌더링하도록 요청합니다.
  • SVG에서 <image xlink:href="slide1.jpg" width="100%" height="100%" />는 컨테이너(이 경우에는 상위 <svg> 요소)를 채우도록 SVG 이미지를 확장하도록 요청합니다.

또한 <svg> 요소에 width 또는 height 값이 지정되지 않았으므로 <svg> 요소는 기본값을 사용합니다.

  • width는 현재 화면 크기와 같습니다.
  • height는 150px과 같습니다.

이러한 사실로 미루어 볼 때 블렌딩된 이미지가 전체 크기가 아닌 이유는 다음과 같습니다.

  1. <svg> 요소의 현재(기본) 높이는 150px입니다.
  2. SVG <image> 요소는 기본적으로 연관된 이미지의 가로 세로 비율을 유지합니다(이 경우에는 4:3 또는 1.3333).
  3. SVG <image> 요소(블렌딩된 이미지)의 height100%로 설정됩니다. 상위 컨테이너의 높이가 150px이므로 SVG <image> 요소의 높이도 150px가 됩니다.
  4. (이전 스크린샷에 표시된 것처럼) 화면의 너비가 150px보다 훨씬 크다고 가정해 봅니다. 2단계와 3단계는 블렌딩된 이미지의 width가 200px(150px x 1.3333 = 200px)이어야 함을 나타냅니다.

여기서, 블렌딩된 이미지가 중앙에 있는 이유는 width 값이 100%(CSS에서 margin: 0 auto와 유사한 효과를 냄)로 설정되어 있기 때문입니다.

앞서 블렌딩된 이미지가 왜 중앙에 있는지와 왜 기본 이미지보다 작은지를 학습했지만 이상하게 블렌딩된 이 이미지가 상위 <svg> 컨테이너보다 큰 이유는 설명해 주지 못합니다. 그 이유는 블렌딩된 이미지가 <svg> 요소의 빨간색 테두리 밖으로 흐르는 이전 스크린샷에서 찾을 수 있습니다. 이러한 동작은 <filter> 요소의 기본 x, y, widthheight 값이 각각 -10%, -10%, 120%, 120%이기 때문에 발생합니다('filter' 요소에 설명되어 있음).

적용된 필터의 기본 height120%이므로 블렌딩된 이미지가 컨테이너 밖으로 20%만큼 확장됩니다(10%는 위로, 10%는 아래로) 이 문제를 해결하기 위해 다음과 같이 <filter> 특성을 설정합니다.


<filter id="myFilter" x="0" y="0" width="100%" height="100%">

그 효과는 예제 4에 나와 있으며(소스를 보려면 마우스 오른쪽 단추 클릭), 이 작업을 통해 상위 요소의 외부로 흐르지 않는 블렌딩된 이미지가 생성됩니다.

예제 4 스크린샷

그리고 앞에서 암시된 것처럼, 블렌딩된 이미지를 전체 크기로 만들려면 <svg><image> 요소 둘 다에 대해 다음과 같이 크기를 제공해야 합니다.

예제 5


<!DOCTYPE html>
<html>

<head>
  <meta http-equiv="X-UA-Compatible" content="IE=10" >
  <meta content="text/html; charset=utf-8" http-equiv="Content-Type">
  <title>Example 5</title>
  <style>
    svg, img {
      display: block;
    }
    
    svg {
      border: 2px red solid;
    }
    
    img {
      border: 2px green solid;
    }  
  </style>
</head>

<body>
  <h1>Note that this example requires a browser that supports SVG filters, 
      such as Internet Explorer 10 or later.</h1>
  <svg width="400" height="300">
    <defs>
      <filter id="myFilter" x="0" y="0" width="100%" height="100%">
        <feImage href="slide2.jpg" result="slide2" />
        <feBlend in="SourceGraphic" in2="slide2" mode="lighten" />
      </filter>
    </defs>   
    <image xlink:href="slide1.jpg" filter="url(#myFilter)" width="400" height="300" /> 
  </svg>
  <img src="slide1.jpg" />
  <img src="slide2.jpg" />
</body>

</html>

다음은 예제 5의 출력을 보여 주는 스크린샷입니다.

예제 5의 출력을 보여 주는 스크린샷

또한 다음과 같이 <svg><image> 요소의 width 값을 100%로 설정하여 블렌딩된 이미지를 중앙에 오게 할 수 있습니다.

예제 6


<!DOCTYPE html>
<html>

<head>
  <meta http-equiv="X-UA-Compatible" content="IE=10" >
  <meta content="text/html; charset=utf-8" http-equiv="Content-Type">
  <title>Example 6</title>
  <style>
    svg {
      display: block;
      border: 2px black solid;
    } 
  </style>
</head>

<body>
  <h1>Note that this example requires a browser that supports SVG filters, 
      such as Internet Explorer 10 or later.</h1>
  <svg width="100%" height="300">
    <defs>
      <filter id="myFilter" x="0" y="0" width="100%" height="100%">
        <feImage href="slide2.jpg" result="slide2" />
        <feBlend in="SourceGraphic" in2="slide2" mode="lighten" />
      </filter>
    </defs>   
    <image href="slide1.jpg" filter="url(#myFilter)" width="100%" height="300" /> 
  </svg>
</body>

</html>

다음은 예제 6의 출력을 보여 주는 스크린샷입니다.

예제 6의 출력을 보여 주는 스크린샷

앞에 나온 모든 코드 예제에서는 mode="lighten"을 사용했습니다. 이 외에도 다음과 같은 mode 값이 있습니다.

  • normal
  • multiply
  • screen
  • darken

마지막 예제는 가능한 모든 mode 값을 사용하여 프로그래밍 방식으로 slide1.jpg와 slide2.jpg를 블렌딩합니다.

예제 7


<!DOCTYPE html>
<html>

<head>
  <meta http-equiv="X-UA-Compatible" content="IE=10" > <!-- For intranet development only. Remove prior to placing the page into production. -->
  <meta content="text/html; charset=utf-8" http-equiv="Content-Type">
  <title>Example 7</title>
</head>

<body>
  <h1>Note that this example requires a browser that supports SVG filters, such as Internet Explorer 10 or later.</h1>
  <svg width="100%" height="100%">
    <defs>
      <!-- "Missing" markup injected via JavaScript. -->
    </defs>   
  </svg>
  <script>
    var defsElement = document.getElementsByTagName('defs')[0];
    var svgElement = document.getElementsByTagName('svg')[0];
    var modeList = ['normal', 'multiply', 'screen', 'darken', 'lighten'];

    for (var i = 0; i < modeList.length; i++) {
      var filterElement = document.createElementNS('http://www.w3.org/2000/svg', 'filter');
      filterElement.setAttribute('id', "filter" + i);
      filterElement.setAttribute('x', 0);
      filterElement.setAttribute('y', 0);
      filterElement.setAttribute('width', '100%');
      filterElement.setAttribute('height', '100%');

      var feImageElement = document.createElementNS('http://www.w3.org/2000/svg', 'feImage');
      feImageElement.setAttribute('href', 'slide2.jpg');
      feImageElement.setAttribute('result', 'slide2');
      filterElement.appendChild(feImageElement);

      var feBlendElement = document.createElementNS('http://www.w3.org/2000/svg', 'feBlend');
      feBlendElement.setAttribute('in', 'SourceGraphic');
      feBlendElement.setAttribute('in2', 'slide2');
      feBlendElement.setAttribute('mode', modeList[i]);
      filterElement.appendChild(feBlendElement);

      defsElement.appendChild(filterElement);
    } // for

    svgElement.appendChild(defsElement);

    for (var i = 0; i < modeList.length; i++) {
      var svgImageElement = document.createElementNS('http://www.w3.org/2000/svg', 'image');
      svgImageElement.setAttribute('href', 'slide1.jpg');
      svgImageElement.setAttribute('x', 0);
      svgImageElement.setAttribute('y', i*304);
      svgImageElement.setAttribute('width', '400');
      svgImageElement.setAttribute('height', '300');
      svgImageElement.setAttribute('filter', 'url(#filter' + i + ')');

      svgElement.appendChild(svgImageElement);
    } // for

    for (var i = 0; i < modeList.length; i++) {
      var svgTextElement = document.createElementNS('http://www.w3.org/2000/svg', 'text');
      svgTextElement.setAttribute('x', 4);
      svgTextElement.setAttribute('y', i*304 + 26);
      svgTextElement.style.fill = "white"; // Equivalent to svgTextElement.setAttribute('fill', 'white')
      svgTextElement.style.fontSize = "2em"; // Equivalent to svgTextElement.setAttribute('font-size', '2em')
      svgTextElement.style.fontWeight = "bold"; // Equivalent to svgTextElement.setAttribute('font-weight', 'bold')
      svgTextElement.appendChild(document.createTextNode(modeList[i]));
      
      svgElement.appendChild(svgTextElement);
    }
  </script>
</body>

</html>

예제 7의 출력은 다음과 같습니다.

예제 7의 출력을 보여 주는 스크린샷

앞에 나온 모든 예제에서는 두 개의 필터 primitive(<feImage><feBlend>)만 사용하여 여러 흥미로운 효과를 만들어냈습니다. 그러나 사용할 수 있는 필터 primitive는 더 많습니다. 이 문서가 작성된 시점에는 16개의 필터 primitive가 있습니다(최신 목록은 필터 효과 참조).

한 필터의 출력은 다른 필터에 대한 입력으로 사용될 수 있으므로 가능한 효과의 수는 매우 많습니다. SFV 필터를 결합하여 흥미로운 결과를 만들어내는 방법에 대한 자세한 내용은 필터 효과를 참조하세요.

관련 항목

필터 효과
Canvas, SVG 및 멀티 터치를 사용하여 타일식 퍼즐 게임을 만드는 방법
HTML5 그래픽
Windows Internet Explorer 9 HTML5 그래픽

 

 

표시:
© 2014 Microsoft