如何在窗体上绘制半透明图像?

5

我想在Delphi窗体上绘制一个半透明的图像,但出于某些原因它无法工作。

这是原始PNG图像(边框是半透明的):
Transparent border

我将图像加载到TImage对象中:

Image1.Transparent := True;
Form1.Color := clWhite;
Form1.TransparentColor := True;
Form1.TransparentColorValue := clWhite;

TImage

这个应用程序:
Application


这张图片不是半透明的。我正在使用一个包含alpha通道的BMP图像,我是否遗漏了什么?


我不明白你是如何在 Delphi 7 的 TImage 控件中使用 PNG 图像的。Delphi 7 不支持 PNG... - Andreas Rejbrand
嗯嗯嗯嗯。它作为PNGObject加载。 - Little Helper
2
D7不支持png格式。您已安装第三方组件。为什么反对第三方组件? - David Heffernan
好的,使用第三方组件!哦哦哦。抱歉,我正在使用TNT Unicode控件。TTntImage。 - Little Helper
谢谢!但是问题来了! - Little Helper
显示剩余6条评论
3个回答

11

我找到了一种解决方案,可以让你只使用Windows API在表单上绘制带有Alpha通道的BMP图像:

const
  AC_SRC_OVER = 0;
  AC_SRC_ALPHA = 1;

type
  BLENDFUNCTION = packed record
    BlendOp,
    BlendFlags,
    SourceConstantAlpha,
    AlphaFormat: byte;
  end;

function WinAlphaBlend(hdcDest: HDC; xoriginDest, yoriginDest, wDest, hDest: integer;
  hdcSrc: HDC; xoriginSrc, yoriginSrc, wSrc, hSrc: integer; ftn: BLENDFUNCTION): LongBool;
  stdcall; external 'Msimg32.dll' name 'AlphaBlend';

procedure TForm4.FormClick(Sender: TObject);
var
  hbm: HBITMAP;
  bm: BITMAP;
  bf: BLENDFUNCTION;
  dc: HDC;
begin
  hbm := LoadImage(0,
    'C:\Users\Andreas Rejbrand\Skrivbord\RatingCtrl.bmp',
    IMAGE_BITMAP,
    0,
    0,
    LR_LOADFROMFILE);
  if hbm = 0 then
    RaiseLastOSError;
  try
    if GetObject(hbm, sizeof(bm), @bm) = 0 then RaiseLastOSError;
    dc := CreateCompatibleDC(0);
    if dc = 0 then RaiseLastOSError;
    try
      if SelectObject(dc, hbm) = 0 then RaiseLastOSError;
      bf.BlendOp := AC_SRC_OVER;
      bf.BlendFlags := 0;
      bf.SourceConstantAlpha := 255;
      bf.AlphaFormat := AC_SRC_ALPHA;
      if not WinAlphaBlend(Canvas.Handle,
        10,
        10,
        bm.bmWidth,
        bm.bmHeight,
        dc,
        0,
        0,
        bm.bmWidth,
        bm.bmHeight,
        bf) then RaiseLastOSError;
    finally
      DeleteDC(dc);
    end;
  finally
    DeleteObject(hbm);
  end;
end;

我使用GIMP软件将PNG图像转换

在这里找到了一个32位RGBA位图here,在这里找到here,结果非常好:


是的,它可以工作。但如果我想在表单周围绘制边框呢? - Little Helper
我想创建可换肤的表单。 - Little Helper
4
好的!顺便提一下,您的代码可以使用常规的gdi函数声明运行,即windows.AlphaBlend(),无需声明常量、记录和函数。 - Sertac Akyuz
1
@Sertac:我非常清楚这一点,但我不确定在旧版Delphi 7中是否在Windows.pas中声明了AlphaBlend。此外,在我的Delphi版本(Delphi 2009)中Windows.pasAlphaBlend的声明非常“丑陋”:function AlphaBlend(DC: HDC; p2, p3, p4, p5: Integer; DC6: HDC; p7, p8, p9, p10: Integer; p11: TBlendFunction): BOOL; stdcall; 但我想我应该写一个脚注来说明这一点。 - Andreas Rejbrand
为什么我在 Stack Overflow 发表的每一篇帖子都被踩得一塌糊涂?!?! - Andreas Rejbrand

1

TransparentColorValue方法不可能奏效,因为它只适用于单色代表完全透明的图像。[此外,您正在使用表单透明颜色而非图像透明颜色!] 上述PNG图像应该具有alpha通道,所以并非每个像素都是显示或透明的,而是每个像素具有0到1之间(例如0.37)的不透明度。也就是说,除了每个像素的R、G和B分量之外,还有一个'alpha'组件A。

然而,上面的图像似乎是损坏的。下面显示了一张“正确”的PNG图像:


(来源:rejbrand.se)

您可以尝试将上面的图像混合到不同的背景中,您会发现阴影混合得很好。

那么,如果有一个“正确”的PNG图像,如何将其绘制到表单上?嗯,在您的情况下这将非常困难,因为Delphi 7不支持PNG图像。它只支持BMP图像,而这些通常没有alpha通道。


Windows 位图通常具有 alpha 通道。 - David Heffernan
@David:是的,但我不确定Delphi 7中的TImage是否可以处理那些东西。可以吗? - Andreas Rejbrand
1
@warren 谁说过文件了?你认为你的计算机内部是如何表示32bpp xp图标的? - David Heffernan
@Robrok:您指的是上面那个名为“Form4”的文件吗?那么您可能正在使用一种非常糟糕的图像文件格式转换器。尝试使用Paint。但是,BMP和alpha通道并不非常兼容,所以如果我是您,我可能不会使用BMP。 - Andreas Rejbrand
无论是BMP还是PNG都行。我正在学习如何在表单上绘制透明图像。 - Little Helper
显示剩余5条评论

1
为什么不尝试将您的PNG绘制到常规BMP的新图像上。在图像2上绘制所需内容,完成后重新绘制/或分配/到图像1中。必定有效...

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接