【问题标题】:Convert Image Color without changing its transparent background转换图像颜色而不更改其透明背景
【发布时间】:2014-07-12 21:16:50
【问题描述】:

在 HTML5 或 Canvas(或任何其他 HTML5 技术)的帮助下,有没有人有一个很好的解决方案来改变非透明区域的颜色。

我用谷歌搜索了很多,找到了一些可以改变图像颜色的解决方案(使用 Canvas),例如,

How do i tint an image with HTML5 Canvas?

Canvas - Change colors of an image using HTML5/CSS/JS?

但这些解决方案也会将透明背景更改为给定颜色(我不想要)。

它是具有透明背景的 stackoverflow png 图像。现在,我想在不影响其透明像素(背景)的情况下更改图像颜色,这样我就可以在 canvas toDataURL 方法的帮助下使用新颜色再次保存图像。

我不确定是否可以使用 HTML5。非常感谢任何帮助。

提前致谢。

*********************已编辑*********************

添加了药丸(胶囊)的新图像。

【问题讨论】:

  • 这可能正是您不想要的,但我通常更改图像颜色的方法只是让它变得有点透明,并将背景图像颜色设置为所需的颜色。跨度>
  • @dcclassics:我认为你误解了我的意思。我有一个带有一些透明像素的 png 图像,比如说,一个 mario(卡通人物)png 图像。因为马里奥是一个字符并且有多项式的一面。我们的图像必须包含一些透明的像素。所以现在,我想在不改变透明像素的情况下改变字符(马里奥)的颜色。
  • 您可能需要canvas.getImageDataputImageData,它们允许您使用RGBA 值逐个像素地编辑画布。请参阅this tutorial 了解一下。

标签: javascript html canvas


【解决方案1】:

一个演示(请参阅下面有关此演示的说明):http://jsfiddle.net/m1erickson/2d7ZN/

您可以使用context.getImageData获取包含图像RGBA像素数据的数组

var imageData=context.getImageData(0,0,canvas.width,canvas.height);

var data=imageData.data;

您可以从那里读取(并可选择更改)每个像素的颜色。

rgba 数组的布局如下:

// top-left pixel (x:0,y:0)

data[0]   red of pixel#0 (0-255)
data[1]   green of pixel#0 (0-255)
data[2]   blue of pixel#0 (0-255)
data[3]   alpha of pixel#0 (opacity: 0-255)

// next pixel (x:1,y:0)

data[4]   red of pixel#1
data[5]   green of pixel#1
data[6]   blue of pixel#1
data[7]   alpha of pixel#1

你可以通过改变数据数组来改变任意像素的R、G、B或A分量

例如,这会将左上角的像素更改为纯红色

data[0]=255;   // red
data[1]=0;     // green
data[2]=0;     // blue
data[3]=255;   // alpha (opacity)

关于透明度:

每个像素的 alpha 分量决定了该像素的透明度。如果您只想修改大部分不透明像素,那么您可以轻松地忽略所有半透明像素,如下所示:

// alpha is 0-255
// ignore pixels with alpha < 200 (ignore all pixels that are mostly semi-transparent)

if( data[3]<200 ) { // don't process this pixel }

最后,您可以使用.putImageData将修改后的像素推回画布

context.putImageData(imageData,0,0);

关于演示的注意事项

使用画布的默认 RGBA 配色方案很难“重新着色”图像。

所以这个演示将 RGB 数据转换为 HSL 颜色方案。这允许更改“颜色”(色调)而不影响像素的其他组件(S=颜色饱和度,L=颜色亮度)。

像素重新着色后,修改后的 HSL 数据将转换回 RGBA 并保存到数据数组中。

【讨论】:

  • 谢谢马克E。它是一个很好的解决方案。虽然,我仍然在努力解决这个问题。我不知道要在图像中更改的颜色。我只想添加用户传递给图像的颜色(这是原始图像颜色+用户传递的颜色的混合)。
  • 我添加了一个新的药丸(胶囊)图片。我想更改用户以十六进制形式传递的颜色。任何关于这方面的指导都会很棒。感谢Adv.
  • 嗯,透明像素的 alpha 值接近于零(可能是 0-10),所以不要更改 alpha 值较低的像素。您的药丸图像具有较浅和较深的颜色。如果要更改药丸的较暗部分,则以较低 rgb 值(较低 rgb 值 == 较暗颜色)的像素为目标。如果要更改药丸的较亮部分,则以具有较高 rgb 值的像素为目标。正如我的回答一样,您应该将所选像素转换为 HSL,并将所选像素的颜色移向用户传递的颜色。这样,图像的饱和度和亮度就会保持不变。
  • 谢谢。我不知道这是否会解决我的特定问题,但我肯定会尝试一下。这也是一个有价值的建议,这个答案也为解决此类问题提供了一个很好的解决方案。所以,接受你的回答。
  • 是否可以在图像本身绘制在画布上之前更改图像数据?
【解决方案2】:

我今天遇到了类似的问题,所以我创建了 Node.js 脚本,它完全符合预期。

const { chunk } = require('lodash');
const { createCanvas, loadImage, createImageData } = require('canvas');

const hexToRgb = (hex) => {

    // Expand shorthand form (e.g. "03F") to full form (e.g. "0033FF")
    const shorthandRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i;
    hex = hex.replace(shorthandRegex, (m, r, g, b) => {

        return r + r + g + g + b + b;

    });

    const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
    return result ? {
        r: parseInt(result[1], 16),
        g: parseInt(result[2], 16),
        b: parseInt(result[3], 16),
    } : null;

};

const convert = async(url, hex) => {

    const { r, g, b } = hexToRgb(hex);
    const baseImage = await loadImage(url);
    const canvas = createCanvas(baseImage.width, baseImage.height);
    const ctx = canvas.getContext('2d');
    ctx.drawImage(baseImage, 0, 0);
    const { data } = ctx.getImageData(0, 0, baseImage.width, baseImage.height);
    const pixels = chunk(data, 4);
    /**
     * @type {unknown[]}
     */
    const convertedPixel = pixels.map((pixel) => {

        pixel[0] = r;
        pixel[1] = g;
        pixel[2] = b;

        return pixel;

    }).reduce((p, n) => [...p, ...n], []);

    const imageData = createImageData(
        new Uint8ClampedArray(convertedPixel),
        baseImage.width, baseImage.height,
    );
    ctx.putImageData(imageData, 0, 0);
    return canvas.toBuffer();

};

【讨论】:

    猜你喜欢
    • 2017-06-06
    • 1970-01-01
    • 2021-10-20
    • 1970-01-01
    • 2017-08-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多