3

我在 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;

不知道哪一部分是错的。这是一个组件的一部分,我正在尝试更改在设计时分配的图像。这是我加载的PNG图像,256x256,透明。

我需要使用那个 TImage,我知道它不是一个按钮。可能有一些组件可以做到这一点。我需要自己制作,因为我正在使用一个特定的库。

我从 PNGFunctions 上的 Gustavo 函数之一获得了 PNGInvertWB 的想法:

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

所以,我根本没有图像经验,这段代码有什么问题?

这是我拥有图像的组件上的样子:

原来的: 原来的

后: 在上面这个函数之后

我使用了 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;

我在哪里更改了 GrayscaleRGB,因为它正在获取每个像素并将其更改为灰度,所以我相信我可以相应地更改为黑色或白色。

4

2 回答 2

0

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

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

尝试这个

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;

你得到什么?

于 2013-12-20T09:10:58.393 回答
0
  1. 然后我想这是因为透明度(将左下角更改为不同的颜色)

我不知道有关此 png 组件的详细信息,也不知道它是否具有像素属性,但将其放在程序的末尾

Line := Image.Scanline[Image.Height - 1];
Line[0].rgbtRed:= 5;
Line[0].rgbtGreen:= 5;
Line[0].rgbtBlue:= 5;

结果有什么变化吗?

  1. 或者你进入调色板代码而不是全色放置断点,你会看到你的代码在哪里中断

如果这是调色板,请在此处添加评论-这会有所不同,因为您不能将颜色更改为白色,而将另一种颜色更改为黑色。你需要三个陡峭的一个变白,例如红黑变白,红变黑

于 2013-12-21T19:11:08.340 回答