在一个base64编码的图片中,是否可以替换某个颜色?

22

有没有办法处理一个 base64 字符串,例如:

.copyIcon {background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAW0lEQVR42mNgQALCi7//J4QZcAFiNOM1hJANBA0h1QC83iHFizDJ/dgww/7/LAQNwKUZbkjDfya8YQZXiCqJagilBmAzhLYGYDNsJBhAMD3gS854NS/6vg+fZgDKvmW19S7PRAAAAABJRU5ErkJggg==") center center no-repeat;}

如何使用JavaScript将一个纯色替换为另一个纯色?

在这个具体的例子中,我有一个图标中的纯色(#13A3F7),我想用另一种纯色(#ff6400)来替换它。

之所以这样做是因为它不是一次性的。我希望能够通过设置将图标更改为任何颜色。

有没有办法实现这个功能?

1个回答

27

以下是一个小函数,它需要三个参数:数据(data)、颜色起始值(colorFrom)和颜色结束值(colorTo),两个颜色都应用十六进制表示。

function changeColInUri(data,colfrom,colto) {
    // create fake image to calculate height / width
    var img = document.createElement("img");
    img.src = data;
    img.style.visibility = "hidden";
    document.body.appendChild(img);

    var canvas = document.createElement("canvas");
    canvas.width = img.offsetWidth;
    canvas.height = img.offsetHeight;

    var ctx = canvas.getContext("2d");
    ctx.drawImage(img,0,0);

    // remove image
    img.parentNode.removeChild(img);

    // do actual color replacement
    var imageData = ctx.getImageData(0,0,canvas.width,canvas.height);
    var data = imageData.data;

    var rgbfrom = hexToRGB(colfrom);
    var rgbto = hexToRGB(colto);

    var r,g,b;
    for(var x = 0, len = data.length; x < len; x+=4) {
        r = data[x];
        g = data[x+1];
        b = data[x+2];

        if((r == rgbfrom.r) &&
           (g == rgbfrom.g) &&
           (b == rgbfrom.b)) {

            data[x] = rgbto.r;
            data[x+1] = rgbto.g;
            data[x+2] = rgbto.b;

        } 
    }

    ctx.putImageData(imageData,0,0);

    return canvas.toDataURL();
}

需要额外添加一个函数将十六进制颜色转换为RGB(以便正确匹配)

function hexToRGB(hexStr) {
    var col = {};
    col.r = parseInt(hexStr.substr(1,2),16);
    col.g = parseInt(hexStr.substr(3,2),16);
    col.b = parseInt(hexStr.substr(5,2),16);
    return col;
}

使用方法如下:

changeColInUri(
    "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAW0lEQVR42mNgQALCi7//J4QZcAFiNOM1hJANBA0h1QC83iHFizDJ/dgww/7/LAQNwKUZbkjDfya8YQZXiCqJagilBmAzhLYGYDNsJBhAMD3gS854NS/6vg+fZgDKvmW19S7PRAAAAABJRU5ErkJggg==",
    "#13A3F7",
    "#ff6400"
);

它将返回一个新的data:image/png; URI,其中颜色已经交换,以下是最终结果的可用jsfiddle链接:

http://jsfiddle.net/V5dU2/

(已在Chrome、Firefox和IE10上测试通过)


伟大的想法。请注意,它需要<canvas>支持,而IE 8及更早版本没有本地支持。 - Paul D. Waite
@PaulD.Waite 在我看来,由于IE 8甚至无法很好地处理数据URI(最大长度为32KB),因此这不应该是一个问题。 - xiaoyi
1
根据我在 caniuse.com 上的阅读,IE 的问题(如您所述,取决于大小)在 HTML 中的数据 URI 中,而不是 CSS 中...如果这有帮助的话。 - adam-asdf
嗨,非常好的答案和脚本。我已经实现了它。但是,在第一次加载时,它似乎总是输出一个透明的PNG。当在用户交互中使用脚本时,它似乎工作正常。有人遇到过这个问题吗? - Redox
2
DOMException: Failed to execute 'getImageData' on 'CanvasRenderingContext2D': The source width is 0 - Vlad

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接