在JavaScript画布上混合两个图像

12

如何混合两个像素数据数组以创建一张图像?并可选使用不同的混合模式?


你有这会是什么样子或者怎样使用的例子吗? - Shane Reustle
3个回答

20

Pixastic是一个专门用于高级canvas应用的框架,这里有混合示例:http://www.pixastic.com/lib/docs/actions/blend/

如果你想独立完成此操作,可以从两张图像中提取像素数据,使用数学方程进行混合,然后将其放入画布中。以下是获取和放置画布像素数据的信息:http://ajaxian.com/archives/canvas-image-data-optimization-tip


更新: 以50-50的比例对2个图像进行Alpha混合的简单示例。 (图片来自http://www.pixastic.com/sample/Butterfly.jpghttp://www.pixastic.com/sample/Flower.jpg

<img src="Butterfly.jpg" id="img1">
<img src="Flower.jpg" id="img2">
<p>Blended image<br><canvas id="canvas"></canvas></p>
<script>
window.onload = function () {
    var img1 = document.getElementById('img1');
    var img2 = document.getElementById('img2');
    var canvas = document.getElementById("canvas");
    var context = canvas.getContext("2d");
    var width = img1.width;
    var height = img1.height;
    canvas.width = width;
    canvas.height = height;

    var pixels = 4 * width * height;
    context.drawImage(img1, 0, 0);
    var image1 = context.getImageData(0, 0, width, height);
    var imageData1 = image1.data;
    context.drawImage(img2, 0, 0);
    var image2 = context.getImageData(0, 0, width, height);
    var imageData2 = image2.data;
    while (pixels--) {
        imageData1[pixels] = imageData1[pixels] * 0.5 + imageData2[pixels] * 0.5;
    }
    image1.data = imageData1;
    context.putImageData(image1, 0, 0);
};
</script>

谢谢,你让我意识到我只需要在谷歌上搜索“混合方程”或类似的关键词,就能找到正确的公式。 - davivid
1
这是一个我之前没有使用过的好的优化技术!看起来是一个非常有用的库 - 虽然我更愿意先学习如何自己实现这些东西。 - davivid
@davivid 当你去查看混合方程式时,你会发现很少有人提到如何处理alpha通道。一般来说,这些方程式假设颜色值使用了预乘alpha,并且_得出的颜色也使用了预乘alpha_。因此,你必须先计算出结果alpha(通常为sourceAlpha + destAlpha * (1-sourceAlpha)),然后将结果颜色除以结果alpha。 - Phrogz
2
...但现在有一份来自Adobe和Canon的规范(草案),其中包括完整的方程式:https://dvcs.w3.org/hg/FXTF/rawfile/tip/compositing/index.html - Phrogz
2
http://dph.am/pixastic-docs/ 仍有可用的文档,而 pixastic.com 现在是一个赌场网站 :-/ - bramchi

4

我已经创建了一个独立的、轻量级的、开源的库,用于将 Photoshop 风格的混合模式从一个 HTML 画布上下文传递到另一个上下文: context-blender。以下是示例用法:

// Might be an 'offscreen' canvas
var over  = someCanvas.getContext('2d');
var under = anotherCanvas.getContext('2d');

over.blendOnto( under, 'screen', {destX:30,destY:15} );

请参阅README了解更多信息。

看起来这会是一个不错的答案,适用于这个问题 - robertc
很棒的库,帮助我完成了一个项目。 - JayCrossler

2
我被赋予的任务是使用JavaScript重新创建this Java小程序(必须适用于平板电脑,并在所有现代浏览器中工作,>IE8)。 我正在使用以下代码创建图像:var image1 = new Image(); 然后设置源:img.src = "some path";

因此,从pepkin88那里,我看到以下函数将通过组合它们的像素数组数据混合两个图像,覆盖第一个图像的先前数据与新的混合数据,最终将新数据放置在画布上,形成混合图像:
window.onload = function () {
var img1 = document.getElementById('img1');
var img2 = document.getElementById('img2');
var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");
var width = img1.width;
var height = img1.height;
canvas.width = width;
canvas.height = height;

var pixels = 4 * width * height;
context.drawImage(img1, 0, 0);
var image1 = context.getImageData(0, 0, width, height);
var imageData1 = image1.data;
context.drawImage(img2, 0, 0);
var image2 = context.getImageData(0, 0, width, height);
var imageData2 = image2.data;
while (pixels--) {
    imageData1[pixels] = imageData1[pixels] * 0.5 + imageData2[pixels] * 0.5;
}
image1.data = imageData1;
context.putImageData(image1, 0, 0); };
然而,如果您查看我负责重新创建的Java小程序,您会发现在您使用指针拖动图像时,混合会实时连续发生,图像不断基于它们重叠的区域进行混合。
因此,我正在寻求修改代码以解决这个问题,并且我不断地获得绘制图像的x、y位置(基于左上角),所有图像的w、h保持静态。
以下代码片段并未包含我所做的一切,只是我认为对您了解重要的内容。
//Rectangle Class from Java converted to JS
function Rectangle(x, y, width, height, src) {
        this.x   = x; 
        this.y   = y; 
        this.w   = width;
        this.h   = height;
        this.img = new Image();
        this.img.src = src;
    }

//Stores instance in rect array
rect[0] = new Rectangle(1, (height - 111)/2, 150, 105, "images/mMain.png");

//Draw method that's called
Rectangle.prototype.draw = function(ctx) {
        //this.checkBound();
        ctx.drawImage(this.img, this.x, this.y, this.w, this.h);
        prepareMix(this.img, this.x, this.y, this.w, this.h);
    }

所以,我正在编写一个“prepareMix”函数,它接收图像信息并使用它来获取和存储图像数据:
 function prepareMix(src, x, y, w, h) {
        
        pixels = 4 * w * h;
        var image = mtx.getImageData(x, y, w, h);
        var imgData = image.data; 
    }

制作一个待办事项列表:
  1. 检测重叠部分
  2. 获取并存储重叠图像数据
  3. 混合重叠区域的数据数组
  4. 用混合后的数据替换重叠的图像数据
  5. 将新数据放置在画布上

1. 检测重叠部分:

计划:存储图像位置并比较位置数据,以了解是否发生重叠。 如果重叠为TRUE,则是哪两个图像发生了重叠?将这些重叠的图像与其他图像区分开来,以便可以对它们调用方法。

js、css、html和图像在此处的zip链接BOX


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