【问题标题】:Fill image with texture/pattern用纹理/图案填充图像
【发布时间】:2015-04-17 05:15:18
【问题描述】:

我正在寻找一种解决方案来更改产品的纹理/图案。

此刻我有:

  1. 一张带有透明背景的沙发的 .png 图片
  2. 纹理的.png图片

使用以下代码:

<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);
}

`

我得到这个结果:

如您所见,整个对象都充满了我的纹理。枕头等的定义不再可见。是否可以让我的纹理成为一种透明蒙版?

我已经可以改变沙发的颜色了:

但我也希望能够在我的沙发上添加图案!

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

【问题讨论】:

  • 1) 用你的图案填充画布。 2) 使用 globalCompositeOperation='luminosity' 并绘制沙发。 3) 使用 globalCompositeOperation='source-in' 并绘制沙发。也许玩 globalAlpha 来调制。这是您可以获得的最接近的结果:您需要一个 3D 模型/3D 渲染器来进行准确的纹理化。
  • @GameAlchemist 你可以使用亮度,但请记住,这是一种不可分离的模式,它必须通过 HSL,所以它的计算机负担要重得多(甚至如果它对后者使用了一些 Adob​​e 魔法)而不是使用简单的 Cb x Cs 的乘法。
  • @KenFyrstenberg :使用亮度不应该是一个问题 1)它是一次性计算 2)GPU 不会介意转换,并且 3)如果你手动做它会无论公式如何,都非常慢。但是在使用“亮度”和接近 0.5 的 alpha 测试您的代码之后,使用乘法的最佳理由是......它看起来更好!
  • @GameAlchemist 这不是问题,只是计算量更大(如果在此处的定制器中大量使用它,或者客户端在较慢的计算机上,则可能会成为问题)。 OP可以考虑到需要优化的东西。是的,同意,手动乘法 (IE) 在任何一种情况下都会很慢。

标签: javascript canvas html5-canvas drawing mask


【解决方案1】:

如果您只是在进行说明性近似,则可以使用混合和合成模式的组合。

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

主要步骤:

  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);
}
&lt;canvas id="canvas" width=600 height=400&gt;&lt;/canvas&gt;

如果您愿意,还可以颠倒绘制图像的顺序等。这只是一种方式的示例。

如果您需要精确的纹理,则无法拍照或使用 3D 软件或手绘纹理。

注意:IE 不支持multiply - 为此,您需要手动遍历像素并将每个组件相乘。

您可以通过这种方式测试支持:

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

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

第二个问题是,如果您最终不得不手动执行此操作(例如在 IE 中),则代码模拟起来会有点复杂,并且会明显变慢。

【讨论】:

  • 正是我想要的!谢谢!
  • 为好答案点赞。我一直忘记新的混合功能!也许如果我说 3 次,它会留在我的记忆中:blending, blending, blending :->
猜你喜欢
  • 1970-01-01
  • 2023-03-26
  • 2015-06-03
  • 1970-01-01
  • 2013-07-27
  • 2013-09-06
  • 2020-05-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多