ChatGPT解决这个技术问题 Extra ChatGPT

如何更改画布元素中元素的不透明度(alpha、透明度)?

使用 HTML5 <canvas> 元素,我想加载一个图像文件(PNG、JPEG 等),将其完全透明地绘制到画布上,然后将其淡入。我已经弄清楚如何加载图像并绘制它到画布,但我不知道如何改变它的不透明度。

这是我到目前为止的代码:

var canvas = document.getElementById('myCanvas');
    
if (canvas.getContext)
{
    var c           = canvas.getContext('2d');
    c.globalAlpha   = 0;
    
    var img     = new Image();
    img.onload  = function() {
        c.drawImage(img, 0, 0);
    }
    img.src     = 'image.jpg';
}

有人会请我指出正确的方向,例如要设置的属性或要调用的函数会改变不透明度吗?


B
Bhuwan

我也在寻找这个问题的答案,(澄清一下,我希望能够绘制具有用户定义的不透明度的图像,例如如何绘制具有不透明度的形状)如果您使用原始形状绘制,您可以设置填充和描边带有 alpha 的颜色来定义透明度。据我现在得出的结论,这似乎不会影响图像绘制。

//works with shapes but not with images
ctx.fillStyle = "rgba(255, 255, 255, 0.5)";

我已经得出结论,设置 globalCompositeOperation 适用于图像。

//works with images
ctx.globalCompositeOperation = "lighter";

我想知道是否有某种第三种设置颜色的方法,以便我们可以为图像着色并轻松使其透明。

编辑:

经过进一步挖掘,我得出结论,您可以在绘制图像之前通过设置 globalAlpha 参数来设置图像的透明度:

//works with images
ctx.globalAlpha = 0.5

如果您想随着时间的推移实现淡化效果,您需要某种改变 alpha 值的循环,这相当简单,实现它的一种方法是 setTimeout 函数,查看它以创建一个循环,您可以从中更改随着时间的推移阿尔法。


globalAlpha 完美运行。是标准的一部分:whatwg.org/specs/web-apps/current-work/multipage/…
准确地说,具有 globalAlpha 属性的不是 canvas 元素,而是您从画布中获取的上下文。
Ian 下面关于 ctx.save() 和 ctx.restore() 的评论防止 globalAlpha 影响画布的其余部分。
在我看来,与其控制画布上绘制的内容的不透明度,它会更简单,并且仍然可以在绘制图像后(仅一次)控制整个画布本身的不透明度。使用通常的 CSS/样式方法来执行此操作(canvaselement.style.opacity='0.3'; 等)稍后使用 CSS3,您甚至可以完全放弃循环,而只让浏览器处理淡入淡出(类似于 - 过渡:NNNms opacity ease-in-out),甚至“动画”淡入淡出。
不幸的是,canvas2d.fillStyle = "rgba(255, 255, 255, 0.5)"; 不起作用。该值必须为十六进制。
I
Ian

使用 globalAlpha 的一些更简单的示例代码:

ctx.save();
ctx.globalAlpha = 0.4;
ctx.drawImage(img, x, y);
ctx.restore();

如果您需要加载 img

var img = new Image();
img.onload = function() {
    ctx.save();
    ctx.globalAlpha = 0.4;
    ctx.drawImage(img, x, y);
    ctx.restore()
};
img.src = "http://...";

笔记:

最后设置“src”,以确保在所有平台上都调用您的 onload 处理程序,即使图像已经在缓存中。

在保存和恢复之间包装对 globalAlpha 之类的更改(实际上使用它们很多),以确保您不会从其他地方破坏设置,特别是当将从事件中调用一些绘图代码时。


globalAlpha 将模糊画布上的所有图像或绘图,这不是您想要的。
@Grumpy - 不,globalAlpha 不会模糊任何东西。它将为所有 后续 绘图设置 alpha(它不会更改已绘制的任何内容),这就是为什么在示例代码中我将其包装在 saverestore 中,以限制它适用于。
不确定 ctx.restore() 是否会恢复 globalAlpha 您可能还需要在最后执行此操作(至少在早期版本的 Chrome 中我必须这样做) ctx.globalAlpha = 1;
@Sean - 如果你不确定,你应该检查一下。它一定是一个非常古老的 Chrome,它现在可以在所有平台上运行:jsfiddle.net/y0z9h9m7
j
james.garriss

编辑:标记为“正确”的答案不正确。

这很容易做到。试试这段代码,用你手边的任何图片替换“ie.jpg”:

<!DOCTYPE HTML>
<html>
    <head>
        <script>
            var canvas;
            var context;
            var ga = 0.0;
            var timerId = 0;
            
            function init()
            {
                canvas = document.getElementById("myCanvas");
                context = canvas.getContext("2d");
                timerId = setInterval("fadeIn()", 100);
            }
            
            function fadeIn()
            {
                context.clearRect(0,0, canvas.width,canvas.height);
                context.globalAlpha = ga;
                var ie = new Image();
                ie.onload = function()
                {
                    context.drawImage(ie, 0, 0, 100, 100);
                };
                ie.src = "ie.jpg";
                
                ga = ga + 0.1;
                if (ga > 1.0)
                {
                    goingUp = false;
                    clearInterval(timerId);
                }
            }
        </script>
    </head>
    <body onload="init()">
        <canvas height="200" width="300" id="myCanvas"></canvas>
    </body>
</html>

关键是 globalAlpha 属性。

在 Win7 上使用 IE 9、FF 5、Safari 5 和 Chrome 12 进行了测试。


L
Lee Goddard

此建议基于画布 2d 上下文中的像素操作。

来自 MDN:

您可以直接在字节级别操作画布中的像素数据

为了操作像素,我们将在这里使用两个函数 - getImageDataputImageData

getImageData 用法:

var myImageData = context.getImageData(left, top, width, height);

putImageData 语法:

context.putImageData(myImageData, x, y); 

其中 context 是您的画布 2d 上下文,xy 是画布上的位置。

因此,要获得红绿蓝和 alpha 值,我们将执行以下操作:

var r = imageData.data[((x*(imageData.width*4)) + (y*4))];
var g = imageData.data[((x*(imageData.width*4)) + (y*4)) + 1];
var b = imageData.data[((x*(imageData.width*4)) + (y*4)) + 2];
var a = imageData.data[((x*(imageData.width*4)) + (y*4)) + 3];

其中 x 是水平偏移,y 是垂直偏移。

使图像半透明的代码:

var canvas = document.getElementById('myCanvas');
var c = canvas.getContext('2d');
var img = new Image();
img.onload  = function() {
   c.drawImage(img, 0, 0);
   var ImageData = c.getImageData(0,0,img.width,img.height);
   for(var i=0;i<img.height;i++)
      for(var j=0;j<img.width;j++)
         ImageData.data[((i*(img.width*4)) + (j*4) + 3)] = 127;//opacity = 0.5 [0-255]
   c.putImageData(ImageData,0,0);//put image data back
}
img.src = 'image.jpg';

您可以制作自己的“着色器” - 请参阅完整的 MDN 文章 here


O
Og2t

你可以。使用destination-out全局复合操作可以快速淡化透明画布。它不是 100% 完美的,有时它会留下一些痕迹,但可以根据需要对其进行调整(即使用“source-over”并用 alpha 为 0.13 的白色填充它,然后淡化以准备画布)。

// Fill canvas using 'destination-out' and alpha at 0.05
ctx.globalCompositeOperation = 'destination-out';
ctx.fillStyle = "rgba(255, 255, 255, 0.05)";
ctx.beginPath();
ctx.fillRect(0, 0, width, height);
ctx.fill();
// Set the default mode.
ctx.globalCompositeOperation = 'source-over';

L
Lee Goddard

我认为这最好地回答了这个问题,它实际上改变了已经绘制的东西的 alpha 值。当被问到这个问题时,也许这不是 api 的一部分。

给定二维上下文 c

function reduceAlpha(x, y, w, h, dA) {
    let screenData = c.getImageData(x, y, w, h);
    for(let i = 3; i < screenData.data.length; i+=4){
        screenData.data[i] -= dA; //delta-Alpha
    }
    c.putImageData(screenData, x, y );
}

这个答案与 7 年前 Soul_man 给出的更详细的答案有何不同?
这是相同的解决方案,但我不得不说这更干净,更容易阅读,所以我很高兴它被添加了。就个人而言,我也会将“c”作为参数添加到函数中,以便您可以将它与分层画布或文档中的多个画布一起使用。
j
jxwd

设置全局 Alpha 绘制具有不透明度的对象,然后设置回正常。

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// globalAlpha = 0.75; ctx.beginPath(); ctx.arc(x1, y1, r1, 0, Math.PI*2); ctx.fillStyle = 颜色; ctx.fill(); ctx.closePath(); ctx.globalAlpha = 1;


c
cen

如果您使用 jCanvas 库,您可以在绘图时使用 opacity 属性。如果您需要淡入淡出效果,只需使用不同的值重绘即可。


M
MPG

你不能。这是即时模式图形。但是您可以通过在其上以不透明度的背景颜色在其上绘制一个矩形来模拟它。

如果图像的颜色不是恒定的,那么它会变得相当棘手。在这种情况下,您应该能够使用像素操作方法。只需在绘制图像之前保存该区域,然后将其与不透明度混合回顶部。


这不是正确答案,请参阅 below
您是对的,虽然您无法更改已绘制到画布中的元素之一的不透明度,但您可以更改整个画布的不透明度。在某些情况下,这可能就足够了。
MPG - 您的评论(5 月 11 日)也是错误的。您可以更改画布的不透明度,但这不是 OP 想要的,也不是上述答案中所建议的。