В холсте HTML5, как замаскировать изображение на фоне моего выбора?

Я попытался сделать это с холстом globalCompositeOperation, но мне не повезло, поэтому я спрашиваю здесь. Здесь есть похожие вопросы, но я не нашел их среди них.

У меня есть слои в области холста, так как (порядок рисования снизу вверх):

  • База холста заполнена чисто белым (#fff, с fillRect)
  • Первое изображение house - это изображение дома. Фон прозрачен. (см. ниже).
  • Второе изображение roofOverlay представляет собой наложение "маскировочное" изображение с красной крышей (может быть любым, но красным для ясности, см. ниже).

Оба изображения занимают весь холст и выстраиваются идеально друг на друга, так что красная площадь крыши соответствует дому.

Затем у меня есть повторяющийся фон repeatPattern, который я хочу использовать ТОЛЬКО внутри красных областей: чтобы заполнить красную область с помощью repeatPattern. (может быть что угодно, но принимать шестиугольники или что-то еще)

В псевдокоде это в идеале должно быть что-то в строках:

roofOverlay.maskBackground(repeatPattern)

(В обозревателе я также хотел бы иметь возможность связываться со значениями HSL фона, но я думаю, что это довольно просто, как только я получаю шаблон даже для отображения)

Ожидаемый результат:

Ожидаемым результатом будет дом, крыша которого текстурирована с изображением repeatPattern.

Примечание. Я знаю об обтравочных контурах с масками, но я не могу использовать их здесь. Пример упрощен, и рисовать все пути для нескольких разных домов было бы слишком много. У меня есть только наложенные png файлы для крыши.

Изображения для справки

Househouse


House roof overlayroofOverlay

Ответ 1

Вот как создать свой "шаблон крыши" поверх вашего "дома", используя "roofOverlay"

enter image description here

Это многочастный процесс:

  • Нарисуйте дом на холсте # 1.
  • Нарисуйте красную крышу. Оверлей на холсте # 2.
  • Установить холст # 2s context.globalCompositeOperation = 'source-in'
  • Нарисуйте свой желаемый узор на холсте # 2
  • Композиция заставит ваш желаемый шаблон заменить красный накладной только в области красного наложения.

Вот скрипка, которая загружает траву на вашей крыше: http://jsfiddle.net/m1erickson/SWP6v/

И вот код, который использует заливку решетки на крыше:

Примечание. Я предполагаю, что вы хотите, чтобы дом и крыша были на отдельных холстах, чтобы вы могли перелистывать различные варианты крыши. Если вам нужно все на одном холсте, вы можете просто нарисовать полотно крыши на холсте дома.

<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css -->
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>

<style>
    body{ background-color: ivory; }
    canvas{border:1px solid red;}
    #container{position:relative;}
    #house{position:absolute; top:0; left:0;}
    #canvas{position:absolute; top:0; left:0;}
</style>

<script>
$(function(){

    var house=document.getElementById("house");
    var ctxHouse=house.getContext("2d");
    var canvas=document.getElementById("canvas");
    var ctx=canvas.getContext("2d");

    var red=new Image();
    red.onload=function(){
       canvas.width=red.width;
       canvas.height=red.height;

       var houseImage=new Image();
       houseImage.onload=function(){
           house.width=houseImage.width;
           house.height=houseImage.height;
           ctxHouse.drawImage(houseImage,0,0);
       }
       houseImage.src="https://dl.dropbox.com/u/1122582/stackoverflow/house.png";

       ctx.drawImage(red,0,0);

        var imageObj = new Image();
        imageObj.onload = function() {
          var pattern = ctx.createPattern(imageObj, 'repeat');
          ctx.globalCompositeOperation = 'source-in';
          ctx.rect(0, 0, canvas.width, canvas.height);
          ctx.fillStyle = pattern;
          ctx.fill();
        };
        imageObj.src = "http://dl.dropbox.com/u/139992952/stackoverflow/lattice.jpg";
    }
    red.src="https://dl.dropbox.com/u/1122582/stackoverflow/roof-overlay.png";

}); // end $(function(){});
</script>

</head>

<body>
<div id="container">
        <canvas id="house" width=300 height=300></canvas>
        <canvas id="canvas" width=300 height=300></canvas>
</div>
</body>
</html>