更改此 png 的 src 后自动更改 png 颜色的问题

problem changing png color automatically after changing the src of this png

这是我想要实现的目标:一个产品设计师,我可以在其中更改图像的 src(我有一个 8 位黑白 png 的集合)并选择此 png 的颜色。

我正在使用 jQuery 和颜色选择器来更改 png 的颜色,它与以下功能配合使用效果很好:

var changeIconColor = (function () {
    var canvas = document.createElement("canvas"), // shared instance
    context = canvas.getContext("2d");
    
    // set image pixel size and hex color
    color = '00ff00';
    canvas.width = 1000;
    canvas.height = 1000;

    function desaturate() {
        var imageData = context.getImageData(0, 0, canvas.width, canvas.height),
            pixels = imageData.data,
            i, l, r, g, b, a, average;

        for (i = 0, l = pixels.length; i < l; i += 4) {
            a = pixels[i + 3];
            if (a === 0) {
                continue;
            } // skip if pixel is transparent

            r = pixels[i];
            g = pixels[i + 1];
            b = pixels[i + 2];

            average = (r + g + b) / 3 >>> 0; // quick floor
            pixels[i] = pixels[i + 1] = pixels[i + 2] = average;
        }

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

    function colorize(color, alpha) {
        context.globalCompositeOperation = "source-atop";
        context.globalAlpha = alpha;
        context.fillStyle = color;
        context.fillRect(0, 0, canvas.width, canvas.height);
        // reset
        context.globalCompositeOperation = "source-over";
        context.globalAlpha = 1;
    }

    return function (iconElement, color, alpha) {
        context.clearRect(0, 0, canvas.width, canvas.height);
        context.drawImage(iconElement, 0, 0, canvas.width, canvas.height);
        desaturate();
        colorize(color, alpha);
        return canvas.toDataURL("image/png", 1);
    };

}());

我在颜色选择器上更改颜色时调用它:

$('#mask_insert_1').each(function () {
    this.src = changeIconColor(this, $( "#colorpicker_insert_1" ).val(), '1');
});

这会将 png 的黑色像素更改为所选颜色。效果很好。

然后我有另一个函数可以更改此 png 的 src :

$("#select_insert_1").change(function(){
    $("#mask_insert_1").show(); 
    $('#mask_insert_1').attr('src','assets/inserts/'+$("#select_insert_1").val()+'.png');
});

当我 select 我的 select 中的另一个选项时,它会更新到 src。 那也行。

但是...当我 select 一个新的 PNG 时,它显示为黑色像素。没关系,应该是这样的。但是我想添加一行代码来在src改变时更新颜色。

我有另一个功能可以在我按下按钮时手动更新 png 的颜色,我试图将它添加到“更改 select”功能中,但它不起作用.. .

$('#mask_insert_1').each(function () { this.src = changeIconColor(this, $( "#colorpicker_insert_1" ).val(), '1'); });

我哪里错了?

非常感谢您阅读我的文章,如果您能提供帮助,我将更加感谢。 AP

当您更改图片的 src 时,图片不会立即更新。您需要做的是向图像添加 onload 事件侦听器并从那里更新它的颜色。

document.getElementById("colorpicker_insert_1").value = "#" + Math.floor(Math.random() * 0xFFFFFF).toString(16).padStart(6, "0");


var changeIconColor = (function () {
    var canvas = document.createElement("canvas"), // shared instance
    context = canvas.getContext("2d");
    
    // set image pixel size and hex color
    color = '00ff00';
    canvas.width = 100;
    canvas.height = 100;

    function desaturate() {
        var imageData = context.getImageData(0, 0, canvas.width, canvas.height),
            pixels = imageData.data,
            i, l, r, g, b, a, average;

        for (i = 0, l = pixels.length; i < l; i += 4) {
            a = pixels[i + 3];
            if (a === 0) {
                continue;
            } // skip if pixel is transparent

            r = pixels[i];
            g = pixels[i + 1];
            b = pixels[i + 2];

            average = (r + g + b) / 3 >>> 0; // quick floor
            pixels[i] = pixels[i + 1] = pixels[i + 2] = average;
        }

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

    function colorize(color, alpha) {
        context.globalCompositeOperation = "source-atop";
        context.globalAlpha = alpha;
        context.fillStyle = color;
        context.fillRect(0, 0, canvas.width, canvas.height);
        // reset
        context.globalCompositeOperation = "source-over";
        context.globalAlpha = 1;
    }

    return function (iconElement, color, alpha) {
        context.clearRect(0, 0, canvas.width, canvas.height);
        context.drawImage(iconElement, 0, 0, canvas.width, canvas.height);
        desaturate();
        colorize(color, alpha);
        return canvas.toDataURL("image/png", 1);
    };

}());

$("#select_insert_1").change(function(){
    $("#mask_insert_1").show(); 
    $('#mask_insert_1').attr('src', $("#select_insert_1").val());

/* show original image */
document.getElementById("img").src = $("#select_insert_1").val();

});

$('#mask_insert_1').each(function () {
    const img = this;
  let src;

  /* add onload event listener */
  img.onload = e =>
  {
    /* do nothing if image generated by changeIconColor() */
    if (img.src !== src)
      img.src = src = changeIconColor(img, $( "#colorpicker_insert_1" ).val(), '1');
  }
  /* change color now */
  img.onload();
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<select id="select_insert_1">
<option value="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4
  //8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==">img 1</option>
<option value="data:image/gif;base64,R0lGODlhEAAQAMQAAORHHOVSKudfOulrSOp3WOyDZu6QdvCchPGolfO0o/XBs/fNwfjZ0frl3/zy7////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAkAABAALAAAAAAQABAAAAVVICSOZGlCQAosJ6mu7fiyZeKqNKToQGDsM8hBADgUXoGAiqhSvp5QAnQKGIgUhwFUYLCVDFCrKUE1lBavAViFIDlTImbKC5Gm2hB0SlBCBMQiB0UjIQA7">img 2</option>
<option value="invalid image data">img 3</option>
</select>
<input id="colorpicker_insert_1" oninput='$("#select_insert_1").trigger("change")'>

<img id="img" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4
  //8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==">

<img id="mask_insert_1" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4
  //8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==">