Delphi,Direct2D,TBitmap和透明度

时间:2016-07-19 09:59:11

标签: delphi transparent direct2d wic

我很难在TBitmap上透明地TDirect2DCanvas绘制TBitmap而不会失去透明度。

创建一个bmp := TBitmap.Create; bmp.Canvas.Brush.Handle := 0; bmp.SetSize(100, 100); bmp.Canvas.Brush.Color := clRed; bmp.Transparent := true; bmp.TransparentColor := clRed; bmp.Canvas.Rectangle(bmp.Canvas.ClipRect); bmp.Canvas.Pen.Color := clGreen; bmp.Canvas.Ellipse(bmp.Canvas.ClipRect); 作为我的绘图操作的后台缓冲区,如下所示:

TDirect2DCanvas

然后我需要将它绘制到我的TBitmap上,但是下面绘制了TForm.Canvas但删除了所有透明度 - 背景颜色绘制为红色,而如果我只是绘制到{{1}然后背景是透明的。

// Drawing onto the TDirect2DCanvas results in a red background
AEventArgs.Canvas.Draw(0, 0, bmp);

// Drawing onto the TForm.Canvas gives the correct result
Self.Canvas.Draw(0, 0, bmp);

我的理解现在引导我进入ID2D1BitmapIWICBitmap接口,因此,我可以尝试使用以下代码从ID2D1Bitmap创建TBitmap(和< em>假设像素格式被复制了一遍):

var
    bmp : TBitmap;
    temp : ID2D1Bitmap;
begin
    // Code to initialize the TBitmap goes here (from above)

    // Create an ID2D1Bitmap from a TBitmap
    temp := AEventArgs.Canvas.CreateBitmap(bmp);

    // Draw the ID2D1Bitmap onto the TDirect2DCanvas
    AEventArgs.Canvas.RenderTarget.DrawBitmap(temp);

现在我有ID2D1Bitmap,结果仍然相同 - 红色背景没有透明度。我认为Direct2D方面使用不同的透明方法是完全可行的,但是查看ID2D1Bitmap的属性并没有提供任何线索。

我的下一个猜测是沿着IWICBitmap界面。

最终,我的问题是:是否有一个更直接或更明显的事情,我从上面错过了,这将允许透明TBitmap被绘制到TDirect2DCanvas表面?或者为了保持透明度,所有这些都是必要的吗?

更新

好的,所以经过多一点挖掘之后,我现在可以将TBitmap转换为IWICBitmap然后转换为ID2D1Bitmap但问题仍然存在 - 透明度存在渲染到TBitmap时,TDirect2DCanvas中的// Create the IWICBitmap from the TBitmap GetWICFactory.CreateBitmapFromHBITMAP(bmp.Handle, bmp.Palette, WICBitmapUsePremultipliedAlpha, wic); wic.GetPixelFormat(pif); // The PixelFormat is correct as `GUID_WICPixelFormat32bppPBGRA` which is // B8G8R8A8_UNORM and PREMULTIPLIED // Create the IWICFormatConverter GetWICFactory.CreateFormatConverter(fc); fc.Initialize(wic, GUID_WICPixelFormat32bppPBGRA, WICBitmapDitherTypeNone, nil, 0.0, WICBitmapPaletteTypeCustom); // Now, create the ID2D1Bitmap AEventArgs.Canvas.RenderTarget.CreateBitmapFromWicBitmap(fc, nil, temp); temp.GetPixelFormat(fmt); // Here, PixelFormat is correct matching the PixelFormat from the IWICBitmap // Draw the bitmap to the Canvas AEventArgs.Canvas.RenderTarget.DrawBitmap(temp); 不会被复制。

// Create the canvas
fCanvas := TDirect2DCanvas.Create(Self.Handle);
fCanvas.RenderTarget.GetPixelFormat(pf); 

// This gives me a PixelFormat of
// B8G8R8A8_UNORM but D2D1_ALPHA_MODE_IGNORE 

结果仍然是一个不透明的位图。

所以我最后要研究的是ID2D1RenderTarget的PixelFormat,它是TDirect2DCanvas的底层渲染目标。

ID2D1RenderTarget

因此,我猜测真正的问题与 create table ma_user.test_mview ( col1 int, col2 int, date_col timestamp ) insert all into ma_user.test_mview values (1,1,SYSDATE) into ma_user.test_mview values (1,2,SYSDATE + 10/1440) into ma_user.test_mview values (1,2,SYSDATE + 30/86400) into ma_user.test_mview values (2,1,SYSDATE + 1/48) into ma_user.test_mview values (2,2,SYSDATE + 1/24) into ma_user.test_mview values (2,2,SYSDATE + 1/72) into ma_user.test_mview values (2,3,SYSDATE + 1/96) SELECT * FROM dual; CREATE MATERIALIZED VIEW ma_user.test_mat_view1 BUILD IMMEDIATE REFRESH complete ON COMMIT as select col1,col2 from ma_user.test_mview where current_date > date_col; PixelFormat忽略alpha这一事实有关。

2 个答案:

答案 0 :(得分:2)

真正的问题不在于您调用的方法,而是在VCL应用程序中默认情况下TBitmap使用24位RGB像素格式的剪切事实,该格式没有Alpha透明度所需的Alpha通道。

如果您想对TBitmap使用Alpha透明度,首先需要将其像素格式设置为2016-07-19 17:48:36,650 DEBUG: security.web.FilterChainProxy - / at position 1 of 12 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter' 2016-07-19 17:48:36,650 DEBUG: web.context.HttpSessionSecurityContextRepository - HttpSession returned null object for SPRING_SECURITY_CONTEXT 2016-07-19 17:48:36,650 DEBUG: web.context.HttpSessionSecurityContextRepository - No SecurityContext was available from the HttpSession: org.apache.catalina.session.StandardSessionFacade@53b1e801. A new one will be created.

https://stackoverflow.com/a/4680460/3636228

另外,不要忘记为希望它透明的每个像素将Alpha通道设置为0。

您看到Direct2D不支持与VCL中使用的相同的透明度,您可以在其中简单地设置透明色,并忽略该特定颜色的每个像素。

答案 1 :(得分:1)

如果您查看 TDirect2DCanvas.CreateBitmap 的源代码,您会看到:

  ...
  if (Bitmap.PixelFormat <> pf32bit) or (Bitmap.AlphaFormat = afIgnored) then
    BitmapProperties.pixelFormat.alphaMode := D2D1_ALPHA_MODE_IGNORE
  else
    BitmapProperties.pixelFormat.alphaMode := D2D1_ALPHA_MODE_PREMULTIPLIED;

所以要让它工作,你必须符合条件:

    bmp.PixelFormat := pf32bit;
    bmp.AlphaFormat := TAlphaFormat.afPremultiplied;

然后你必须准备每个像素的 alpha 通道。在您的情况下,红色是透明的,因此您应该执行以下操作:

for y := 0 to bmp.Height - 1 do begin
  Line := bmp.Scanline[y];
  for x := 0 to bmp.Width - 1 do begin
    if (line[x].r =255) and (line[x].g = 0) and (line[x].b = 0) then
    Line[x].A := 0
  else
    Line[x].A := 255;
end;

然后它来了:

temp := AEventArgs.Canvas.CreateBitmap(BMP);
AEventArgs.Canvas.RenderTarget.DrawBitmap(temp);

我花了整个周末才自己弄明白,希望对你或其他人有帮助。