用纹理/图案填充图像

7
我正在寻找一种解决方案,用于更改产品的纹理/图案。
目前我有以下材料:
1. 一张透明背景的沙发.png图片 enter image description here 2. 一张织物纹理的.png图片 enter image description here 以下是相关代码:
<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);
}

我得到了这个结果:enter image description here

正如您所看到的,整个物体都被我的纹理填满了。枕头等的定义已经不再可见。有没有可能让我的纹理成为一种透明蒙版?

我已经能够改变沙发的颜色:enter image description here

但我也想能够在我的沙发上加入图案!

任何帮助将不胜感激,非常抱歉我的英语不好。


  1. 用你的图案填充画布。
  2. 使用globalCompositeOperation='luminosity' 并绘制沙发。
  3. 使用globalCompositeOperation='source-in' 并绘制沙发。可以尝试调整globalAlpha来进行调节。但这仍然无法达到最准确的纹理效果:你需要一个3D模型/ 3D渲染器才能完成准确的纹理处理。
- GameAlchemist
@GameAlchemist,你可以使用亮度,但请记住这是一种不可分离的模式,必须通过HSL进行处理,因此它比使用乘法更加计算密集(即使它在后者中使用了一些Adobe魔法)。乘法只是Cb x Cs。 - user1693593
@KenFyrstenberg:使用亮度不应该是一个问题,因为1)它只需要计算一次,2)GPU不会在转换时出现问题,3)如果你手动计算,无论公式如何都会非常慢。但是,在测试了您的代码并使用“亮度”和alpha接近0.5之后,使用乘法的最好原因是...它看起来更好! - GameAlchemist
@GameAlchemist 这不是问题,只是计算量更大(如果在此处使用频繁,或客户端在较慢的计算机上,则可能成为问题)。如果需要优化,OP可以考虑这一点。是的,同意,在任何情况下手动乘法(IE)都会很慢。 - user1693593
1个回答

10

如果你只是需要一个形象化的近似值,你可以使用混合和合成模式的组合。

首先要确保您的主图像具有透明度-这对于合成很重要(在以下演示中我进行了粗略的截断)。

Demo result

主要步骤:

  1. 绘制图案
  2. 使用混合模式multiply在上面绘制主图像
  3. 使用合成模式destination-in在上面绘制主图像-这将制作一个剪贴版

如果要缩小图案的大小,可以使用图像的较小版本,以较小的尺寸绘制临时画布并将其用作图案,或者使用图案本身的新变换方法。

演示

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>

如果你喜欢的话,也可以颠倒绘制图像的顺序等。这只是其中一种方法的示例。

如果需要精确的纹理,则必须拍摄照片或使用3D软件或手绘纹理。

注意:IE不支持multiply - 为了解决这个问题,你需要手动迭代每个像素并将每个分量相乘。

你可以通过以下方式测试是否支持:

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

可以在评论中提到混合模式luminosity,当然也可以使用它。我只想指出一些需要考虑的事情。首先,这是一种不可分离的混合模式,意味着它会通过HSL颜色模型依赖于所有组件。这使得它更加计算密集。

其次,如果你最终不得不手动执行此操作(例如在IE中),则代码会比较复杂,而且速度明显变慢。


1
正是我所需要的!谢谢! - ZheMann
点赞给出好答案。我总是忘记新的混合能力!也许如果我说三遍,它就会牢记在我的记忆中:混合,混合,混合 :-> - markE

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接