如何在Delphi中将PNG图像的颜色从白色更改为黑色?

如何在Delphi中将PNG图像的颜色从白色更改为黑色?,delphi,png,delphi-xe2,tpngimagelist,Delphi,Png,Delphi Xe2,Tpngimagelist,我使用的是Delphi XE2中Gustavo Daud 1.4版的TPNGList 它包含一些PNG 256x256图像,我将其用作按钮图像 然而,需要改变背景颜色,并且图像的对比度不好 所以我现在有黑色背景的白色图像 我需要把它们换成黑色作为背景光 有透明度,应该保持透明度。只有白色像素。但是,通用的源到目标函数也很好 编辑: 我尝试了以下建议,但只得到了黑框或白框: procedure PNGInvertWB(Image: TPngImage; AWhite: Boolean); p

我使用的是Delphi XE2中Gustavo Daud 1.4版的TPNGList

它包含一些PNG 256x256图像,我将其用作按钮图像

然而,需要改变背景颜色,并且图像的对比度不好

所以我现在有黑色背景的白色图像

我需要把它们换成黑色作为背景光

有透明度,应该保持透明度。只有白色像素。但是,通用的源到目标函数也很好

编辑: 我尝试了以下建议,但只得到了黑框或白框:

procedure PNGInvertWB(Image: TPngImage; AWhite: Boolean);

  procedure WBInvertRGB(var R, G, B: Byte);
  var
    color: LongInt;
  begin
    if AWhite then
    begin
      if RGB(R, G, B) = clWhite then
      begin
        Color := ColorToRGB(clBlack);
        R := GetRValue(Color);
        G := GetGValue(Color);
        B := GetBValue(Color);
      end;
    end
    else
    begin
      if RGB(R, G, B) = clBlack then
      begin
        Color := ColorToRGB(clWhite);
        R := GetRValue(Color);
        G := GetGValue(Color);
        B := GetBValue(Color);
      end;
    end;
  end;

var
  X, Y, PalCount: Integer;
  Line: PRGBLine;
  PaletteHandle: HPalette;
  Palette: array[Byte] of TPaletteEntry;
begin
  if not (Image.Header.ColorType in [COLOR_GRAYSCALE, COLOR_GRAYSCALEALPHA]) then begin
    if Image.Header.ColorType = COLOR_PALETTE then begin
      PaletteHandle := Image.Palette;
      PalCount := GetPaletteEntries(PaletteHandle, 0, 256, Palette);
      for X := 0 to PalCount - 1 do
        WBInvertRGB(Palette[X].peRed, Palette[X].peGreen, Palette[X].peBlue);
      SetPaletteEntries(PaletteHandle, 0, PalCount, Palette);
      Image.Palette := PaletteHandle;
    end
    else begin
      for Y := 0 to Image.Height - 1 do begin
        Line := Image.Scanline[Y];
        for X := 0 to Image.Width - 1 do
          WBInvertRGB(Line[X].rgbtRed, Line[X].rgbtGreen, Line[X].rgbtBlue);
      end;
    end;
  end;
end;
我使用以下代码调用此代码:

procedure TDBNavigator.UpdateColor;
var
  PNGImage: TPngImage;
  HCColor : TColor;

  procedure Invert(AImage: TImage; AWhite: boolean);
  begin
    ConvertToPNG(AImage.Picture.Graphic, PNGImage);
    PNGInvertWB(PNGImage, not AWhite);
    AImage.Picture.Graphic := PNGImage;
  end;

begin
  Color := ThemeManager.CurrentPallete.Color[FThemeColor];

  HCColor := ThemeManager.CurrentPallete.HighContrast(FThemeColor);
  if HCColor <> FCurrentColor then
  begin
    Invert(uiPrevious, HCColor = clWhite);
    Invert(uiNext,     HCColor = clWhite);
    Invert(uiInsert,   HCColor = clWhite);
    Invert(uiPost,     HCColor = clWhite);
    Invert(uiCancel,   HCColor = clWhite);
    Invert(uiDelete,   HCColor = clWhite);
    Invert(uiRefresh,  HCColor = clWhite);
    FCurrentColor := HCColor;
  end;
end;
所以,我根本没有图像方面的经验,这段代码有什么问题

这是在我有图像的组件上的外观:

原件:

之后:

我使用了PNGFunctions中的以下函数来尝试此操作:

procedure MakeImageGrayscale(Image: TPngImage; Amount: Byte = 255);

  procedure GrayscaleRGB(var R, G, B: Byte);
  var
    X: Byte;
  begin
    X := Round(R * 0.30 + G * 0.59 + B * 0.11);
    R := Round(R / 256 * (256 - Amount - 1)) + Round(X / 256 * (Amount + 1));
    G := Round(G / 256 * (256 - Amount - 1)) + Round(X / 256 * (Amount + 1));
    B := Round(B / 256 * (256 - Amount - 1)) + Round(X / 256 * (Amount + 1));
  end;

var
  X, Y, PalCount: Integer;
  Line: PRGBLine;
  PaletteHandle: HPalette;
  Palette: array[Byte] of TPaletteEntry;
begin
  //Don't do anything if the image is already a grayscaled one
  if not (Image.Header.ColorType in [COLOR_GRAYSCALE, COLOR_GRAYSCALEALPHA]) then begin
    if Image.Header.ColorType = COLOR_PALETTE then begin
      //Grayscale every palette entry
      PaletteHandle := Image.Palette;
      PalCount := GetPaletteEntries(PaletteHandle, 0, 256, Palette);
      for X := 0 to PalCount - 1 do
        GrayscaleRGB(Palette[X].peRed, Palette[X].peGreen, Palette[X].peBlue);
      SetPaletteEntries(PaletteHandle, 0, PalCount, Palette);
      Image.Palette := PaletteHandle;
    end
    else begin
      //Grayscale every pixel
      for Y := 0 to Image.Height - 1 do begin
        Line := Image.Scanline[Y];
        for X := 0 to Image.Width - 1 do
          GrayscaleRGB(Line[X].rgbtRed, Line[X].rgbtGreen, Line[X].rgbtBlue);
      end;
    end;
  end;
end;

我已经改变了灰度B,因为它得到了每个像素并将其改变为灰度,所以我相信我可以相应地改变为黑色或白色。

很高兴看到你有什么原始的a,执行此代码后得到什么

问题是: 你们真的确定整个背景的颜色等于黑色或白色,还是接近黑色或接近白色? 因为你们比较的是精确的颜色RGB(R,G,B)=白色

试试这个

procedure WBInvertRGB(var R, G, B: Byte);
  var
    color: LongInt;
  begin
    if AWhite then
    begin
      if ((R>240) and (G>240) and (B>240)) then
      begin
        Color := ColorToRGB(clBlack);
        R := GetRValue(Color);
        G := GetGValue(Color);
        B := GetBValue(Color);
      end;
    end
    else
    begin
      if ((R<15) and (G<15) and (B<15)) then
      begin
        Color := ColorToRGB(clWhite);
        R := GetRValue(Color);
        G := GetGValue(Color);
        B := GetBValue(Color);
      end;
    end;
  end;
过程WBRGB(变量R,G,B:字节);
变量
颜色:长型;
开始
如果是白色的话
开始
如果((R>240)和(G>240)和(B>240)),那么
开始
颜色:=色度GB(clBlack);
R:=GetRValue(颜色);
G:=GetGValue(颜色);
B:=GetBValue(颜色);
结束;
结束
其他的
开始
如果((R
  • 然后我想这是因为透明度(将左下角更改为其他颜色)
  • 我不知道这个png组件的细节,也不知道它是否有像素属性 但把这个放在程序的末尾

    Line := Image.Scanline[Image.Height - 1];
    Line[0].rgbtRed:= 5;
    Line[0].rgbtGreen:= 5;
    Line[0].rgbtBlue:= 5;
    
    结果有什么变化吗

  • 或者你在Palette代码里面比全彩 放置断点,您将看到代码在哪里中断

  • 如果这是调色板,请在此处添加注释-这会有所不同,因为您不能将颜色更改为白色,而将另一种颜色更改为黑色。您需要三次浸渍,一次将白色更改为红色-黑色,一次将白色更改为白色,另一次将红色更改为黑色

    我会保留一对外部准备/修改的图像集。如果涉及部分透明度,则会进行抗锯齿(部分)零件在非预期的颜色值背景下会看起来不好。谢谢,我已经测试了你的建议,并保持不变。我已经更新了问题并在前后添加了图片。它会根据选择将所有像素变为白色或黑色。这就像获取所有背景像素并进行转换一样。但是它应该请透明,不确定这是否意味着没有像素或某种代码。您还会看到我用来派生函数的原始函数。非常感谢。
    Line := Image.Scanline[Image.Height - 1];
    Line[0].rgbtRed:= 5;
    Line[0].rgbtGreen:= 5;
    Line[0].rgbtBlue:= 5;