在画布中替换特定的颜色和它的阴影

时间:2016-05-04 19:41:50

标签: 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"; 

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

除了我的代码之外,还有办法做到这一点吗?

谢谢

P.S。我的比赛在那里进行: http://www.crownprintsart.com/color 用户名:您的电子邮件地址 密码:crownprintsdemo

2 个答案:

答案 0 :(得分:2)

将Luma转移到Alpha通道

在方法中我建议我们可以先根据&#34;亮度&#34;将黑色数据转换为alpha通道。的颜色。这将保持抗锯齿,这是沿着边缘的各种阴影的原因,并允许我们使用合成模式。

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

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

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

使用阈值

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

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

手动颜色混合

我们也可以手动混合颜色。使用其中一个通道的值作为标准化亮度/灰度值,并根据此值混合两种颜色(伪):

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

使用合成模式的示例

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

stage 1 stage 2

最终结果

result

&#13;
&#13;
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);
}
&#13;
body {background:#777}
&#13;
<canvas id=c></canvas>
&#13;
&#13;
&#13;

答案 1 :(得分:0)

您可以检查颜色是否接近特定值,而不是检查确切的值。可能有更好的方法,但这是我的解决方案:

var precision = 10;

var replaceColor = {
    r: 0,
    g: 0,
    b: 0,
    a: 255,
};

var isInRange = (
    r >= replaceColor.r - precision &&
    r <= replaceColor.r + precision &&
    g >= replaceColor.g - precision &&
    g <= replaceColor.g + precision &&
    b >= replaceColor.b - precision &&
    b <= replaceColor.b + precision &&
    a >= replaceColor.a - precision &&
    a <= replaceColor.a + precision
);

if(isInRange) {

}

希望这有帮助