HTML5 Canvas에서 저비용 및 로컬 동작 가능 블러(Blur) 표현

개요



배경



Canvas상에서 흐림(Blur)을 실시할 수 있는 JS 라이브러리는 많이 있습니다만, 모두 픽셀 처리를 하기 위해 고품질인 것이지만 고부하이므로, 스마트폰용으로 액션 게임을 만드는 것 같은 상황이라고 채용하기 어렵습니다.
또, 픽셀 처리를 하는 관계로, 로컬 동작이라고 브라우저에 의해 시큐러티(동일 출신 폴리시)에 저해 제대로 동작하지 않습니다.

참고:
canvas의 getImageData가 조금 귀찮아 (특히 로컬에서 움직일 경우)
JavaScript에서 로컬 파일 액세스 권한 정책

한편, CSS에서 Canvas 요소를 blur로 흐리게 할 수는 있지만, 이쪽은 내부 처리용으로 작성한 Canvas에는 효과가 없고, 흐림 있음 Canvas를 흐림 없음 Canvas에 합성하면 흐림이 반영되지 않습니다.

그래도 역시 흐리게 표현하고 싶다



다소 품질이 희생되지만
- 픽셀 처리하지 않음
- CSS를 사용하지 않음
- 저부하
- 로컬 환경에서도 작동

을 가능하게 하는 흐림 표현을 소개합니다.

구현



Canvas에는 안티 앨리어싱 기능이 있습니다.



Canvas에 이미지를 표시할 때 1.0~0.5배로 축소 표시하면 2x2 샘플링으로 안티앨리어싱이 걸리는 것 같습니다.
0.5배를 밑도면 샘플링의 사정으로 들쭉날쭉합니다.
참고:
Html5 canvas drawImage: how to apply antialiasing

앤티앨리어싱



작게 그린 것을 확대하면 흐림 출력을 얻을 수 있을 것 같습니다.
또, 2배까지의 확대로 억제하면 적당한 퀄리티를 유지할 수 있을 것 같습니다.

작게 그려서 확대



불러온 이미지에 흐린 문자를 추가하여 표시해 봅니다.
<!DOCTYPE html>
<html>
<body>
<canvas></canvas>
<script>
    var img = new Image();
    img.src = 'sample.jpg';
    img.onload = function() {
        var canvas = document.getElementsByTagName('canvas')[0];
        canvas.width = img.width;
        canvas.height = img.height;
        var text = 'Blur Effect';

        // 0.5倍, 0.25倍の内部キャンバス生成
        var canvasBlur050 = document.createElement("canvas");
        canvasBlur050.width = canvas.width * 0.5;
        canvasBlur050.height = canvas.height * 0.5;
        var canvasBlur025 = document.createElement("canvas");
        canvasBlur025.width = canvas.width * 0.25;
        canvasBlur025.height = canvas.height * 0.25;

        // 普通に画像を表示
        var context = canvas.getContext('2d');
        context.drawImage(img, 0, 0);
        context.fillStyle = '#FFFF00';
        context.strokeStyle = '#FF0000';
        context.font = '64px Arial';
        context.fillText(text, 50, canvas.height * 0.33);
        context.strokeText(text, 50, canvas.height * 0.33);

        // 0.25倍の内部キャンバスに文字描画
        var contextBlur025 = canvasBlur025.getContext('2d');
        contextBlur025.save();
        contextBlur025.setTransform(0.25, 0, 0, 0.25, 0, 0);
        contextBlur025.fillStyle = '#FFFF00';
        contextBlur025.strokeStyle = '#FF0000';
        contextBlur025.font = '64px Arial';
        contextBlur025.fillText(text, 50, canvas.height * 0.66);
        contextBlur025.strokeText(text, 50, canvas.height * 0.66);
        contextBlur025.restore();

        // 0.5倍の内部キャンバスに拡大
        var contextBlur050 = canvasBlur050.getContext('2d');
        contextBlur050.drawImage(canvasBlur025, 0, 0, canvasBlur025.width, canvasBlur025.height, 0, 0, canvasBlur050.width, canvasBlur050.height);

        // 元のキャンバスに拡大して合成
        context.drawImage(canvasBlur050, 0, 0, canvasBlur050.width, canvasBlur050.height, 0, 0, canvas.width, canvas.height);
</script>
</body>
</html>

결과




조금 거친 생각도 듭니다만, 리얼타임 처리로 이 퀄리티라면 문제 없을 것입니다.

응용


  • 이라 스토야 구름이 떠있는 푸른 하늘의 일러스트 (배경 소재)
  • 이라 스토 야 매화 꽃의 그림
  • 이라스토야 니콜라 테슬라의 캐리커처 일러스트

  • 를 사용하여 피사계 심도와 같은 표현

    Canvas 배율은 원경 0.4, 인물 1.0, 근경 0.25입니다.
  • 흐림 방향이 요소의 중앙에서가 아니라 왼쪽 위에서이므로 겹칠 때주의하십시오.
  • 흐림 상태를 동적으로 변경하는 데는 많은 노력이 필요합니다 (매번 내부 Canvas 크기를 변경해야합니다)
  • 흐림이 거칠기 때문에 부하와의 트레이드 오프 옵션으로
  • 좋은 웹페이지 즐겨찾기