JavaScript 过滤器RGB

标签 java javascript image canvas

我目前正在将 Java 转换为 JavaScript,需要更改一些图像的颜色。

现在每个图像都在 Image 类中加载,图像如下所示:

Example image

它是一个作为字符集的PNG,发送的数据被映射到图像中的每个字符。

现有的 Java 代码如下所示:

class VDColorFilter extends RGBImageFilter
{
    int fg;
    int bg;
    final int[] colors;

    public VDColorFilter(final int fgc, final int bgc) {
        super();
        this.colors = new int[] { 0, 16711680, 65280, 16776960, 255, 16711935, 65535, 16777215 };
        this.fg = fgc;
        this.bg = bgc;
        this.canFilterIndexColorModel = true;
    }

    public int filterRGB(final int x, final int y, int rgb) {
        if (rgb == -1) {
            rgb = (0xFF000000 | this.colors[this.bg]);
        }
        else if (rgb == -16777216) {
            rgb = (0xFF000000 | this.colors[this.fg]);
        }
        return rgb;
    }
}

我希望能够对我的图像执行同样的操作,但是是在 JavaScript 中。我对 Java 没有太多经验,因此我不确定 filterRGB 如何针对 colors 数组实际应用 RGB 结果。

当然,这只是对图像进行黑色着色,而不是白色。

有没有模仿这个的库?如果没有,达到相同结果的最佳方法是什么?

最佳答案

您可以使用 getImageData()putImageData() 过滤图像。这将需要实现跨域资源共享(CORS),例如图像来自与页面相同的服务器(浏览器中的安全机制)。

如果该部分没问题,让我们使用您的图像做一个示例 -

如果您的图像有 Alpha channel 而不是白色背景,那就最好了。这将允许您使用复合运算符直接更改颜色,而无需解析像素。

您可以通过两种方式执行此操作:

  1. 一劳永逸地去除背景,然后使用复合运算符(推荐)
  2. 用颜色替换所有黑色像素

使用第一种方法,您只需解析像素一次。每次需要更改颜色时,只需使用复合运算符(请参阅下面的演示 2)。

使用复合运算符

这里有一个方法,先打出背景。我们将为此使用无符号 32 位缓冲区,因为这比使用字节数组更快。

我们可以使用 View 的缓冲区来转换字节缓冲区并为其创建第二个 View :

var data32 = new Uint32Array(idata.data.buffer);

详细信息请参阅下面的代码:

var img = new Image();
img.crossOrigin = "";
img.onload = punchOut;
img.src = "//i.imgur.com/8NWz72w.png";

function punchOut() {
  
  var canvas = document.createElement("canvas"),
      ctx = canvas.getContext("2d");

  document.body.appendChild(this);
  document.body.appendChild(canvas);
  
  // set canvas size = image size
  canvas.width = this.naturalWidth; 
  canvas.height = this.naturalHeight;
  
  // draw in image
  ctx.drawImage(this, 0, 0);
  
  // get pixel data
  var idata = ctx.getImageData(0, 0, canvas.width, canvas.height),
      data32 = new Uint32Array(idata.data.buffer),  // create a uint32 buffer
      i = 0, len = data32.length;

  while(i < len) {
    if (data32[i] !== 0xff000000) data32[i] = 0;    // if not black, set transparent
    i++
  }
  
  ctx.putImageData(idata, 0, 0);                    // put pixels back on canvas
}
body {background:#aaa}

现在我们有了透明图像,我们可以使用合成模式来改变它的颜色。我们需要使用的模式是“source-atop”:

var img = new Image();
img.crossOrigin = ""; img.onload = punchOut;
img.src = "//i.imgur.com/8NWz72w.png";
function punchOut() {
  var canvas = document.querySelector("canvas"), ctx = canvas.getContext("2d");
  canvas.width = this.naturalWidth; 
  canvas.height = this.naturalHeight;  
  ctx.drawImage(this, 0, 0);
  var idata = ctx.getImageData(0, 0, canvas.width, canvas.height),
      data32 = new Uint32Array(idata.data.buffer), i = 0, len = data32.length;
  while(i < len) {if (data32[i] !== 0xff000000) data32[i] = 0;  i++}
  ctx.putImageData(idata, 0, 0);
  
  // NEW PART --------------- (see previous demo for detail of the code above)
  
  // alter color using composite mode
  // This will replace existing non-transparent pixels with the next drawn object
  ctx.globalCompositeOperation = "source-atop";
  
  function setColor() {
    for (var y = 0; y < 16; y++) {
      for (var x = 0; x < 6; x++) {
        var cw = (canvas.width - 1) / 6,
            ch = (canvas.height - 1) / 16,
            cx = cw * x,
            cy = ch * y;
        
        // set the desired color using fillStyle, here: using HSL just to make cycle
        ctx.fillStyle = "hsl(" + (Math.random() * 360) + ", 100%, 80%)";
    
        // fill the area with the new color, due to comp. mode only existing pixels
        // will be changed
        ctx.fillRect(cx+1, cy+1, cw-1, ch-1);
        }
      }
  }
  setInterval(setColor, 100);
  
  // to reset comp. mode, use:
  //ctx.globalCompositeOperation = "source-over";
}
body {background:#333}
<canvas></canvas>

最后,使用drawImage()根据每个字符的映射和单元格计算来选择每个字母(例如,请参阅我为您提供的关于drawImage用法的previous answer)。

  • 使用字符串定义字符映射
  • 使用 map 和 indexOf() 查找字母
  • 计算图像中 x 和 y 的映射索引
  • 使用 drawImage() 将该字母绘制到输出 Canvas 中的 x/y 位置

随机字母

var img = new Image();
img.crossOrigin = ""; img.onload = punchOut;
img.src = "http://i.imgur.com/8NWz72w.png";
function punchOut() {
  var canvas = document.querySelector("canvas"), ctx = canvas.getContext("2d");
  canvas.width = this.naturalWidth; 
  canvas.height = this.naturalHeight;  
  ctx.drawImage(this, 0, 0);
  var idata = ctx.getImageData(0, 0, canvas.width, canvas.height),
      data32 = new Uint32Array(idata.data.buffer), i = 0, len = data32.length;
  while(i < len) {if (data32[i] !== 0xff000000) data32[i] = 0;  i++}
  ctx.putImageData(idata, 0, 0);
  ctx.globalCompositeOperation = "source-atop";  

  function setColor() {
    for (var y = 0; y < 16; y++) {
      for (var x = 0; x < 6; x++) {
        var cw = (canvas.width - 1) / 6,
            ch = (canvas.height - 1) / 16,
            cx = cw * x,
            cy = ch * y;
        ctx.fillStyle = "hsl(" + (Math.random() * 360) + ", 100%, 80%)";
        ctx.fillRect(cx+1, cy+1, cw-1, ch-1);
        }
      }
  }
  setColor();

  // NEW PART --------------- (see previous demo for detail of the code above)
  
  var dcanvas = document.createElement("canvas"), xpos = 0;
  ctx = dcanvas.getContext("2d");

  document.body.appendChild(dcanvas);
  
  for(var i = 0; i < 16; i++) {
    var cw = (canvas.width - 1) / 6,
        ch = (canvas.height - 1) / 16,
        cx = cw * ((Math.random() * 6)|0),  // random x
        cy = ch * ((Math.random() * 16)|0); // random y
    ctx.drawImage(canvas, cx+1, cy+1, cw-1, ch-1, xpos, 0, cw-1, ch-1);
    xpos += 16;
  }
  
}
body {background:#333}
<canvas></canvas>

关于JavaScript 过滤器RGB,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29780446/

相关文章:

java - Cookie 域包含点?

javascript - Jquery Mobile "tap"事件错误

image - 使用 node.js 从图像文件中获取像素数组

c# - Xamarin IF 语句匹配图像按钮及其背景

java - 没有 switch 和条件语句的极端情况逻辑的设计模式

java - Android HashSet 无法转换为 LinkedHashSet

javascript - 使用pdfMake创建PDF后如何下载zip文件

image - 在 magento 中压缩上传的图像

java - 打印没有额外空白或线条的二维数组

java - 编译多个java文件的Ubuntu脚本?