Fill image with texture/pattern

2019-02-18 07:06发布

I'm looking for a solution to change the texture/pattern for a product.

At this moment i have:

  1. A .png picture of a couch with a transparent background enter image description here
  2. A .png picture of a textureenter image description here

With the following code:

<canvas id="a" width="800" height="500">Canvas not supported on your browser</canvas>

var width = $(window).width();
var height = $(window).height();

var c = document.getElementById("a");
var ctx = c.getContext("2d");

var can2 = document.createElement('canvas');
document.body.appendChild(can2)

can2.width = c.width;
can2.height = c.height;
var ctx2 = can2.getContext("2d");


var test = new Image();
test.src = "Images/newBank.png";
test.onload = function () {
    ctx2.drawImage(test, 0, 0);
};

var img = new Image();
img.src = "Images/texturetrans.png";
img.onload = function () {
    ctx2.globalCompositeOperation = 'source-in';
    var ptrn = ctx2.createPattern(img, 'repeat');
    ctx2.fillStyle = ptrn;
    ctx2.fillRect(0, 0, can2.width, can2.height);
}

`

I get this result: enter image description here

As you can see, the whole object is filled with my texture. No definitions of the pillows etc. are visible anymore. Is it possible to let my texture be a sort of transparent mask?

I'm already able to change the color of the couch: enter image description here

But I'd like to be able to also add a pattern to my couch!

Any help will be appreciated and I'm already very sorry for my bad English.

1条回答
Animai°情兽
2楼-- · 2019-02-18 07:35

If you're just after an illustrative approximation you can use a combination of blending and composition modes.

First thing is to make sure your main image has transparency - this is important for composition to work (I made a rough cut-off in the following demo).

Demo result

Main steps:

  1. Draw the pattern
  2. Draw the main image on top with blending mode multiply
  3. Draw the main image on top with compositing mode destination-in - this will make a cut-out

If you want to reduce the size of the pattern you can either do this by using a smaller version of the image, draw to a temporary canvas at a smaller size and use that as pattern, or use the new transform methods on the pattern itself.

Demo

var img1 = new Image, img2 = new Image, cnt = 2,
    canvas = document.getElementById("canvas"),
    ctx = canvas.getContext("2d");

// image loading for demo (ignore)
img1.onload = img2.onload = function() {if (!--cnt) go()};
img1.src = "//i.imgur.com/8WqH9v4.png";       // sofa
img2.src = "//i.stack.imgur.com/sQlu8.png";   // pattern

// MAIN CODE ---
function go() {

  // create a pattern  
  ctx.fillStyle = ctx.createPattern(img2, "repeat");
  
  // fill canvas with pattern
  ctx.fillRect(0, 0, canvas.width, canvas.height);
  
  // use blending mode multiply
  ctx.globalCompositeOperation = "multiply";
  
  // draw sofa on top
  ctx.drawImage(img1, 0, 0, img1.width*.5, img1.height*.5);
  
  // change composition mode
  ctx.globalCompositeOperation = "destination-in";
  
  // draw to cut-out sofa
  ctx.drawImage(img1, 0, 0, img1.width*.5, img1.height*.5);
}
<canvas id="canvas" width=600 height=400></canvas>

You can also reverse the order of which image is drawn etc., if you prefer. This is just an example of one way.

If you need accurate texture then there is no way around to either take photos or use a 3D software, or hand-drawn the textures.

NOTE: IE does not support multiply - For this you need to manually iterate through the pixels and multiply each component with each other.

You can test for support this way:

ctx.globalCompositeOperation = "multiply";
if (ctx.globalCompositeOperation === "multiply") {
    // blend as above
}
else {
    // iterate and blend manually
}

Blending mode luminosity is mentioned in comments and this can be used too of course. I just want to point a couple of things to consider. The first is that this is a non-separable blending mode meaning it depends on all components as it goes through the HSL color model. This makes it a bit more compute intensive.

The second is that if you end up having to do this manually (in for example IE) the code is a bit more complex to emulate, and will be noticeably slower.

查看更多
登录 后发表回答