大多数 browser-supported 改变简单PNG图像颜色的方法?

Most browser-supported method to change the color of a simple PNG image?

在网站构建过程中,我在设计中遇到了鼠标悬停样式的方向(由我解释):

这很简单,可以用 js(甚至 css)进行图像交换...但这让我深思。网站上将有几十个这样的图标链接——每个都与文本配对,每个都可能需要额外的颜色,或者调整蓝色。为任何额外的颜色创建每个图像的新版本将是一件令人头疼的事情,如果需要调整任何颜色,那将是一场噩梦。如果您可以使用 css 在一个地方控制文本和图像颜色,那不是很好吗?

我做了一些研究,关于影响图像颜色的流行观点似乎分​​为使用 CSS3 蒙版或将整个作品放在 SVG 中。 CSS 蒙版因其简单性而成为一个非常有吸引力的选择,但有 one glaring support gap - whereas SVG is recommended by W3C 但似乎依赖于 .svg 格式的图像(.png 解决方案变得复杂且不稳定)。

那么,有没有人知道可以让我有效地更改平面 .png 图像颜色并提供足够浏览器支持的解决方案? simplicity/elegance 的奖励积分,但我会接受任何只需要 .png 图像路径和十六进制颜色的内容。谢谢!


编辑 1: 郑重声明,IE9-10 超出了此处的范围 - 我们只关注 8 和 11。谢谢!


编辑 2: 其他(失败的)注意事项

我考虑过简单地为每个图标创建一个倒置的 "stencil" 并将其覆盖在背景颜色上。然而,这给我们的用户和内容编辑带来了问题,因为这些图标将在其他地方使用,而白色背景上的白色模板是无用的。

另请阅读答案 on this related question,但过滤器似乎不接受十六进制值,也未得到完全支持。图标字体可能有效,但 extensible/modifiable 对 non-savvy 用户来说并不容易 - 这里非常需要 "upload-to-cms" 功能。

答案和演示

I've solved the problem, here is a JSFiddle.

优点

  • 非常好用。
  • 您可以 select 任何格式的任何颜色 JavaScript。
  • 您的图标可以是白色以外的任何颜色。

缺点

  • 为了兼容所有颜色格式,需要tinycolor.js库作为依赖。 (但是:如果您创建自己的颜色转换函数,则可以删除此

  • 它只适用于 IE9+,因为它使用 HTML5 canvas。 (尽管老实说,为 IE 编写代码总是很痛苦)。

  • 源图像必须在同一台服务器上,因为 canvas 不能从 cross-origin 源中被污染,并且您无法从中获取数据,这就是为什么演示中的源图像位于 Data URI. (However: there is a solution(如果您有兴趣的话)。

HTML

<input type="text" value="#669dbb">
<button>Change color</button>
<img src="data:image/png;base64,(..)">

非常简单,<input> 表示您希望图像更改为的颜色,<button> 用于应用更改。 (顺便说一句,原始值是您的默认图标上的浅蓝色)。

JavaScript

var img = document.querySelector("img");
var button = document.querySelector("button");
var text = document.querySelector("input");
var canvas = document.createElement("canvas");
var context = canvas.getContext("2d");

button.onclick = function () {
    changeColor(text.value);
};

changeColor = function (inputColor) {
    canvas.setAttribute("width", img.width);
    canvas.setAttribute("height", img.height);
    context.drawImage(img, 0, 0);
    var dataObject = context.getImageData(0, 0, canvas.width, canvas.height);
    var data = dataObject.data;
    for (var i = 0; i < data.length; i += 4) {
        var r = data[i],
            g = data[i + 1],
            b = data[i + 2],
            a = data[i + 3];
        var notTransparent = a != 0;
        var nonBackground = ( notTransparent && r != 255 && g != 255 && b != 255 );
        if ( nonBackground ) {
            var input = tinycolor(inputColor);
            var rgb = input.toRgb();
            data[i] = rgb.r;
            data[i + 1] = rgb.g;
            data[i + 2] = rgb.b;
            data[i + 3] = a;
        }
    }
    context.putImageData(dataObject, 0, 0);
    img.src = canvas.toDataURL();
}

说明

好的,这是怎么回事,我将把我的解释集中在 changeColor() 函数上,因为其他代码块只是后台工作。

  • 首先,我们将 <img> 的宽度和高度与 <canvas> 相匹配。
  • 然后,我们将图像绘制到canvas。
  • 然后,我们从整个canvas中得到像素数组数据。 (更多关于 canvas pixel manipulation
  • 然后我们读取数据(这是一个很长的数组)并获取每个像素值。
    • 数组[0] = 红色
    • 数组[1] = 绿色
    • 数组[2] = 蓝色
    • 数组[3] = Alpha.
  • 然后,我们检查像素是否不是背景像素,确保它既不透明也不白色。
  • 如果不是,我们获取输入颜色并将其设为 RGB。
  • 然后,我们修改像素数据并更新canvas。
  • 最后,我们从 canvas 得到一个 <img> 来源,方法是将其转换为 Data URI,然后我们更新 <img>.

还有一件事

现在,虽然这可能很酷,但它需要很多 grunt-work 才能开始,所以我让你更容易,这是一个库,可以让你做你想要:AmazingIcon.js (Github)

它还没有完善,但可以胜任,下面是它的工作原理。

HTML(头)

<script src=tinycolor.js></script>
<script src=amazingicon.js></script>

HTML(正文)

<a class="amazingIcon" href="some-url" data-src="icon-image-url">icon-label</a>

很简单,我们使用data-src创建一个pseudo-custom属性。

JavaScript

AmazingIcon.parseDocument();

AmazingIcon.hover(function(icon,ev){
    icon.setColor("lightblue");
});

AmazingIcon.parseDocument() 函数会将任何带有 class amazingIcon 的锚点转换为神奇图标。

AmazingIcon.hover(callback) 函数将悬停事件应用于所有令人惊叹的图标,悬停事件函数将接收两个 (icon,event) 参数,您可以相应地对其进行操作。 (有关文档的更多信息)

CSS

.AmazingIconObject{
    /* Display icons in the same row */
      display: inline-block;
    /* Aligning icons vertically inside parent */
      vertical-align: top;
    /* Centering labels */
      text-align: center;
    /* Sepparation between the icons */
      margin-right: 5px;
    /* Break label to fit icon width */
      word-wrap: break-word;
    /* Sets the width of the anchor (not the icon) */
      width: 100px;
    /* The following properties are design-subjective */
      font-family: Verdana;
      font-weight: bold;
      color: lightcoral;
      margin-right: 5px;
      text-decoration: none;
}

很简单,如果你想知道更多它是如何工作的,当然一切都在 github,请随意复制和修改代码,请你和任何其他读者。

演示

由于难以使用 non-crossorigin 来源进行演示,我将只向您展示一张它看起来像的图像。

希望对您有所帮助,再见!