javascript - 替换 Canvas 中的特定颜色及其阴影

标签 javascript html canvas

我正在尝试制作网络工具,允许人们替换我正在销售的简单 2 色图像中的颜色。我使用的图像以 jpg 格式保存。我确实到处查看,并且确实想出了以下代码:

var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");

img = new Image();

img.onload = function() {
 canvas.width = img.width;
 canvas.height = img.height;
 context.drawImage(img,0,0,canvas.width,canvas.height); 

 var imageData = context.getImageData(0, 0, canvas.width, canvas.height);
 var pixelArray = imageData.data;
 var length = pixelArray.length / 4; 

 for (var i = 0; i < length; i++) {
    var index = 4 * i;

    var r = pixelArray[index];
    var g = pixelArray[++index];
    var b = pixelArray[++index];
    var a = pixelArray[++index];

    if (r === 0 && g === 0 && b === 0 & a === 255) {
        pixelArray[--index] = 47; 
        pixelArray[--index] = 255; 
        pixelArray[--index] = 173; 
    }
 }

 context.putImageData(imageData, 0, 0);
}

img.src = "assets/images/tijana-mala.jpg"; 

不幸的是,我意识到许多像素不仅仅是“黑色或白色”,而且还有不同的色调。图像的复杂性相当简单,我出售报价:背景上的文本,使用各种字体。

有没有办法在我的代码之外做到这一点?

谢谢

附注我的竞争对手成功了: http://www.crownprintsart.com/color 用户名:您的电子邮件地址 密码:crownprintsdemo

最佳答案

将亮度传输到 Alpha channel

在我建议的方法中,我们可以首先根据颜色的“亮度”将黑色数据转换为 Alpha channel 。这将保留抗锯齿功能,这是边缘出现各种阴影的原因,并允许我们使用合成模式。

尽管没有说明,如果黑色不是纯黑色(即实际上是深灰色),我们可以通过组合使用简单的阈值来压缩范围。

然后使用 source-atop 合成模式为白色背景着色,最后使用 destination-atop 绘制新的黑色颜色(现在是 Alpha channel )合成模式。

使用合成模式可以更好地提高性能,因为您不必费心手动混合颜色。

使用阈值

另一种方法是使用阈值。如果颜色(灰色/亮度)高于某个值,则将其转换为颜色 A,如果低于某个值,则将其转换为颜色 B 等。

但是,这样做的问题是,抗锯齿边缘会失去其目的,并成为边缘的实心部分,这是不可取的,因为边缘最终会呈锯齿状,就像没有抗锯齿一样。我们可以通过使用非常高分辨率的原始图像来减少问题,然后将其缩小,但代价是需要迭代更多的数据。

手动混色

我们还可以手动混合颜色。使用其中一个 channel 的值作为归一化亮度/灰度值,并根据该值混合两种颜色(伪):

luma = redColor / 255;  // or green/blue assuming image is grey-scale
newColor = Math.round(colorA * luma + colorB * (1 - luma));

使用组合模式的示例

此示例使用第一种技术。下面的灰色是浏览器背景色,用于显示 Alpha channel -

stage 1 stage 2

最终结果

result

var img = new Image,
    ctx = c.getContext("2d");

img.onload = setup;
img.crossOrigin = "";
img.src = "https://i.imgur.com/ZJHabAD.jpg";

function setup() {
  // draw in image (scaled for demo)
  c.width = this.naturalWidth;
  c.height = this.naturalHeight;
  ctx.drawImage(this, 0, 0);
  
  // create alpha channel from "black" pixels
  var idata = ctx.getImageData(0, 0, c.width, c.height),
      data = idata.data;

  for(var i = 0, v; i < data.length; i += 4) {
    v = data[i];
    if (v < 30) v = 0;  // compress grey to black (arbitrary threshold here)
    data[i+3] = v;
  }
  
  ctx.putImageData(idata, 0, 0);
  
  // replace white color
  ctx.fillStyle = "#AF4979";
  ctx.globalCompositeOperation = "source-atop";
  ctx.fillRect(0, 0, c.width, c.height);
 
  // replace "black" (alpha)
  ctx.fillStyle = "#C6AF47";
  ctx.globalCompositeOperation = "destination-atop";
  ctx.fillRect(0, 0, c.width, c.height);
}
body {background:#777}
<canvas id=c></canvas>

关于javascript - 替换 Canvas 中的特定颜色及其阴影,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37036631/

相关文章:

JavaScript:如何使用字符串作为一段代码

javascript - 需要幻灯片 div 在更改幻灯片时将元素向下推

javascript - 如何通过单击按钮将从内容脚本检索到的值存储到文本框中

Android - 触摸绘图

javascript - Canvas getImageData().data 返回半张图像

python - 查找与其他 Canvas 对象重叠的对象 - Python tkinter

javascript - 使用 CamanJS 的图像查看器/编辑器

javascript - Ajax Bing map 版本 7 - 移动和删除图钉 - 初学者教程

javascript - 代码在 Codepen 中有效,但不适用于我的桌面文件

javascript - 对 VueJS 生命周期钩子(Hook)的误解