我在透明背景上有一个包含艺术品的画布。我像这样去饱和它:
boardCtx.fillStyle = "rgba(0, 0, 0, 1.0)";
boardCtx.globalCompositeOperation = 'saturation';
boardCtx.fillRect(0, 0, boardCanvas.width, boardCanvas.height);
并发现透明背景已变为不透明黑色。我不希望饱和度混合模式改变alpha通道......我做错了什么?我目前的解决方案是在去饱和之前复制画布并使用它来遮盖不饱和副本的黑色背景,但这涉及另一个画布和大画面...不理想。
答案 0 :(得分:1)
ctx.filter
2D上下文filter可用于将各种过滤器应用于画布。
ctx.filter = "saturate(0%)";
ctx.drawImage(ctx.canvas,0,0);
但如果存在抗锯齿/透明度,则会增加alpha,从而降低质量。
要解决此问题,您需要使用ctx.globalCompositeOperation = "copy"
操作。
ctx.filter = "saturate(0%)";
ctx.globalCompositeOperation = "copy";
ctx.drawImage(ctx.canvas,0,0);
// restore defaults;
ctx.filter = "";
ctx.globalCompositeOperation = "source-over";
这将停止修改Alpha通道。
警告。检查filter页面底部的浏览器支持。如果没有支持,如果使用ctx.globalCompositeOperation = "saturation"
答案 1 :(得分:1)
混合模式仅适用于前景(源)图层而不考虑Alpha通道,而常规复合操作仅使用Alpha通道 - 这就是您看到不透明结果的原因。
要解决,只需在使用合成模式“目标输出”的去饱和处理后向现有内容添加“剪裁调用”,然后重新绘制图像:
// draw image 1. time
boardCtx.fillStyle = "#000";
boardCtx.globalCompositeOperation = 'saturation';
boardCtx.fillRect(0, 0, boardCanvas.width, boardCanvas.height);
boardCtx.globalCompositeOperation = 'destination-out';
// draw image again 2. time
这也将恢复原始的Alpha通道。
如果艺术作品不是图像源,那么您可以通过将画布绘制到临时画布来拍摄快照,然后使用上述相同的步骤将该临时画布用作图像源。
你也可以像在另一个答案中那样使用过滤器(还有一个过滤器“灰度”,它比“饱和”效率略高)但目前只有Chrome(来自v52)和Firefox(来自v49)支持{{1 Android上的Webview(来自v52)。
filter
第三种方法是迭代像素并进行去饱和。仅当您打算支持不支持混合模式的旧浏览器时,才需要这样做。
/*
CanvasRenderingContext2D.filter (EXPERIMENTAL, On Standard Track)
https://developer.mozilla.org/docs/Web/API/CanvasRenderingContext2D/filter
DESKTOP:
Chrome | Edge | Firefox | IE | Opera | Safari
----------+-----------+-----------+-----------+-----------+-----------
52 | ? | 49° | - | - | -
°) 35-48: Behind flag canvas.filters.enabled set to true.
MOBILE:
Chrome/A | Edge/mob | Firefox/A | Opera/A |Safari/iOS | Webview/A
----------+-----------+-----------+-----------+-----------+-----------
52 | ? | 49° | - | - | 52
°) 35-48: Behind flag canvas.filters.enabled set to true.
*/
var ctx = c.getContext("2d"), i = new Image;
i.onload = function() {
ctx.drawImage(this, 0, 0); // draw image normally
ctx.globalCompositeOperation = "saturation"; // desaturate (blending removes alpha)
ctx.fillRect(0, 0, c.width, c.height);
ctx.globalCompositeOperation = "destination-in"; // knock out the alpha channel
ctx.drawImage(this, 0, 0); // by redrawing image using this mode
};
i.src = "//i.stack.imgur.com/F4ukA.png";