如何在不改变其模式的情况下更改HTML5 Canvas中图像的颜色

我想在保持图像的形状,效果和轮廓的同时更改此图像的背景颜色。

  function drawImage(imageObj,x, y, width, height){ var canvas = document.getElementById('canvas01'); var context = canvas.getContext('2d'); context.drawImage(imageObj, x, y, width, height); } var image = new Image(); image.onload = function(){ drawImage(this, 400, 100, 320, 450); }; image.src ="images/658FFBC6.png";  

Luma保存

冒着类似于现有答案的风险,我想指出一个小而重要的差异,使用略有不同的方法。

关键是保留图像中的亮度分量(即阴影细节,皱纹等),因此需要两个步骤来通过globalCompositeOperation使用混合模式控制外观(或者,使用RGB和RGB之间的转换的手动方法)如果必须支持旧浏览器,则为HSL颜色空间):

  • saturation ”:将改变下一个绘制元素的色度(强度,饱和度)并将其应用于canvas上的现有内容,但保留亮度和色调。
  • hue ”:将从光源获取色度和亮度,但如果愿意,可根据下一个绘制的元素改变色调或颜色。

由于这些是混合模式(忽略alpha通道),我们还需要使用合成剪辑结果作为最后一步。

color混合模式也可以使用,但它会改变亮度,这可能是也可能不是。 在许多情况下,差异可能很微妙,但也非常明显,具体取决于失去亮度/阴影定义的目标色度和色调。

因此,为了获得保持亮度和色度的高质量结果,这些或多或少是主要步骤(假设空白canvas):

 // step 1: draw in original image ctx.globalCompositeOperation = "source-over"; ctx.drawImage(img, 0, 0); // step 2: adjust saturation (chroma, intensity) ctx.globalCompositeOperation = "saturation"; ctx.fillStyle = "hsl(0," + sat + "%, 50%)"; // hue doesn't matter here ctx.fillRect(0, 0); // step 3: adjust hue, preserve luma and chroma ctx.globalCompositeOperation = "hue"; ctx.fillStyle = "hsl(" + hue + ",1%, 50%)"; // sat must be > 0, otherwise won't matter ctx.fillRect(0, 0, c.width, c.height); // step 4: in our case, we need to clip as we filled the entire area ctx.globalCompositeOperation = "destination-in"; ctx.drawImage(img, 0, 0); // step 5: reset comp mode to default ctx.globalCompositeOperation = "source-over"; 

50%亮度(L)将保持原始亮度值。

实例

单击复选框以查看对结果的影响。 然后使用不同的色度和色调设置进行测试。

 var ctx = c.getContext("2d"); var img = new Image(); img.onload = demo; img.src = "//i.stack.imgur.com/Kk1qd.png"; function demo() {c.width = this.width>>1; c.height = this.height>>1; render()} function render() { var hue = +rHue.value, sat = +rSat.value, l = +rL.value; ctx.clearRect(0, 0, c.width, c.height); ctx.globalCompositeOperation = "source-over"; ctx.drawImage(img, 0, 0, c.width, c.height); if (!!cColor.checked) { // use color blending mode ctx.globalCompositeOperation = "color"; ctx.fillStyle = "hsl(" + hue + "," + sat + "%, 50%)"; ctx.fillRect(0, 0, c.width, c.height); } else { // adjust "lightness" ctx.globalCompositeOperation = l < 100 ? "color-burn" : "color-dodge"; // for common slider, to produce a valid value for both directions l = l >= 100 ? l - 100 : 100 - (100 - l); ctx.fillStyle = "hsl(0, 50%, " + l + "%)"; ctx.fillRect(0, 0, c.width, c.height); // adjust saturation ctx.globalCompositeOperation = "saturation"; ctx.fillStyle = "hsl(0," + sat + "%, 50%)"; ctx.fillRect(0, 0, c.width, c.height); // adjust hue ctx.globalCompositeOperation = "hue"; ctx.fillStyle = "hsl(" + hue + ",1%, 50%)"; ctx.fillRect(0, 0, c.width, c.height); } // clip ctx.globalCompositeOperation = "destination-in"; ctx.drawImage(img, 0, 0, c.width, c.height); // reset comp. mode to default ctx.globalCompositeOperation = "source-over"; } rHue.oninput = rSat.oninput = rL.oninput = cColor.onchange = render; 
 body {font:16px sans-serif} 
 

全球综合业务

2D上下文属性ctx.globalCompositeOperation对于各种图像处理任务非常有用。 有关MDN上globalCompositeOperation的更多信息

您可以将图像转换为canvas,这样您就可以对其进行编辑。

 function imageToCanvas(image){ const c = document.createElement("canvas"); c.width = image.width; c.height = image.height; c.ctx = c.getContext("2d"); // attach context to the canvas for eaasy reference c.ctx.drawImage(image,0,0); return c; } 

您可以使用globalCompositeOperation = "color"为图像着色

 function colorImage(image,color){ // image is a canvas image image.ctx.fillStyle = color; image.ctx.globalCompositeOperation = "color"; image.ctx.fillRect(0,0,image.width,image.height); image.ctx.globalCompositeOperation = "source-over"; return image; } 

不幸的是,这也会覆盖alpha像素,因此您需要使用原始图像作为遮罩来恢复alpha像素。

 function maskImage(dest,source){ dest.ctx.globalCompositeOperation = "destination-in"; dest.ctx.drawImage(source,0,0); dest.ctx.globalCompositeOperation = "source-over"; return dest; } 

然后你有一个彩色图像

例。

在他的例子中,我用一系列颜色为图像着色,并添加了一个function,将图像的canvas副本恢复为原始图像。 如果从页面获取图像作为元素,则使用naturalWidthnaturalHeight因为widthheight属性可能与图像分辨率不匹配。

 const ctx = canvas.getContext("2d"); const image = new Image; var colCopy; image.src = "http://sofzh.miximages.com/javascript/Kk1qd.png"; image.onload = () => { colCopy = imageToCanvas(image); const scale = canvas.height / image.naturalHeight; ctx.scale(scale, scale); ctx.drawImage(colCopy, 0, 0); for (var i = 32; i < 360; i += 32) { restoreImage(colCopy, image); colorImage(colCopy, "hsl(" + i + ",100%,50%)"); maskImage(colCopy, image); ctx.drawImage(colCopy, 150 * i / 16, 0); } } function imageToCanvas(image) { const c = document.createElement("canvas"); c.width = image.naturalWidth; c.height = image.naturalHeight; c.ctx = c.getContext("2d"); // attach context to the canvas for easy reference c.ctx.drawImage(image, 0, 0); return c; } function restoreImage(dest, source) { dest.ctx.clearRect(0, 0, dest.width, dest.height); dest.ctx.drawImage(source, 0, 0); return dest; } function colorImage(dest, color) { // image is a canvas image dest.ctx.fillStyle = color; dest.ctx.globalCompositeOperation = "color"; dest.ctx.fillRect(0, 0, dest.width, dest.height); dest.ctx.globalCompositeOperation = "source-over"; return dest; } function maskImage(dest, source) { dest.ctx.globalCompositeOperation = "destination-in"; dest.ctx.drawImage(source, 0, 0); dest.ctx.globalCompositeOperation = "source-over"; return dest; } 
 canvas { border: 2px solid black; }