【问题标题】:Getting PNG images drawn to canvas using image's Alpha channel使用图像的 Alpha 通道将 PNG 图像绘制到画布上
【发布时间】:2018-02-11 19:50:22
【问题描述】:

我正在制作一个程序来显示抽奖结果历史和结果数据的统计数据。我想显示球的图像而不仅仅是它们的数字,所以我制作了一组带有数字的 3D 外观球的 png 图像,小的 32x32 和更大的 48x48。如:

即使在 Alpha 通道上,这些显然也是带有抗锯齿边缘的圆形。我无法将它们加载到 TImageList 并显示在画布上而不会失去 alpha 透明度,我得到的最好的方法是硬蒙版。相反,我在设计时为每个球创建了一个 TImage,并加载了球的 png 图像。为了通过球号轻松引用它们,我声明了var Balls: array[1..59] of TImage;,我将其连接到表单的 OnCreate 中的每个 TImage,即简单的 Balls[1] := Image01; Balls[2] := Image02; 等等。我使用这些 TImage 的 OnMouseEnter/OnMouseLeave/OnClick 事件来突出显示和选择它们。实际上,我有另一个 TImage 来表示比球稍大的选择高光,当鼠标悬停在球上时,它会出现在 Ball 的 TImage 后面。所有这一切都很好,但现在我想在 TDrawGrid 中使用相同的图像,它主要将所有结果数据显示为文本,但我希望使用 OnDrawCell 事件将球号显示为图像。

问题是:我找不到将带有 alphachannel 的图像复制到 DrawGrid 画布上的方法 - 我在使用 CopyRect 时收到错误消息:'can only modify an image if it contains a bitmap' 所以我发现在线解决方案创建一个 TBitmap 并复制 Ball 的 TImage 但它丢失了 alpha 混合并且背景是黑色的。我只想能够将 alphachannel 图像复制到背景可以是任何颜色的任何画布(例如 clBtnFace)。

const
  CellPadding = 4;
  Colnames: array [0..15] of string = ('Draw','Day','Date','Month','Year','1st','2nd','3rd','4th','5th','6th','B','Jackpot','Wins','Machine','Ball set');

procedure TLottoResults.DrawGrid1DrawCell(Sender: TObject; ACol, ARow: Integer; Rect: TRect; State: TGridDrawState);
var
  dcBall: Integer;
  dcRect: TRect;
  dcBmp: TBitmap;
begin
  DrawGrid1.Canvas.Brush.Style := bsClear;
  if ARow = 0 then
  begin
    DrawGrid1.Canvas.Font.Name := 'Tahoma';
    DrawGrid1.Canvas.Font.Size := 12;
    DrawGrid1.Canvas.Font.Style := [fsBold];
    DrawGrid1.Canvas.TextRect(Rect, Rect.Left+CellPadding, Rect.Top,  Colnames[ACol])
  end
  else
  begin
    if gdSelected in State then DrawGrid1.Canvas.Brush.Color := clGreen
    else DrawGrid1.Canvas.Brush.Color := clNavy;
    DrawGrid1.Canvas.FillRect(Rect);
    DrawGrid1.Canvas.Font.Color := clWhite;
    if ACol in [5..11] then  // columns to display images instead of text
    begin
      // StringGrid1 is what the raw CSV data is loaded into first and is kept invisible,
      // and it's contents are copied to DrawGrid1 for actual display.
      if TryStrToInt(StringGrid1.Cells[ACol, ARow-1], dcBall)then
      begin
        if dcBall in [1..59] then
        begin
          dcBmp := TBitmap.Create;
//          Following disabled code is what has been tried in various combinations
//          dcBmp.PixelFormat := pf32bit;
//          dcBmp.TransparentMode := tmFixed;
//          dcBmp.TransparentColor := clBtnFace;
//          dcBmp.AlphaFormat := afDefined;
//          Balls[dcBall].Picture.Graphic.Transparent := True;
          dcBmp.Assign(Balls[dcBall].Picture.Graphic);
          Balls[dcBall].Picture.Bitmap := dcBmp;
//          FreeAndNil(dcBmp);

          dcRect := TRect.Create(0,0,32,32);
          if DataLoaded then
            DrawGrid1.Canvas.CopyRect(TRect.Create(Rect.Left+2, Rect.Top+2, Rect.Left+32+2, Rect.Top+32+2), Balls[dcBall].Canvas, dcRect);
//          DrawGrid1.Canvas.Draw(Rect.Top,Rect.Left,Balls[dcBall].Picture.Graphic); // Draw draws in the wrong place, why?
        end
        else
        begin // Display as text if not in range 1 to 59
          DrawGrid1.Canvas.Font.Name := 'Courier New';
          DrawGrid1.Canvas.Font.Size := 12;
          DrawGrid1.Canvas.Font.Style := [];
          DrawGrid1.Canvas.TextRect(Rect, Rect.Left+CellPadding, Rect.Top+(DrawGrid1.RowHeights[ARow] div 2)-(DrawGrid1.Canvas.TextHeight('Ag') div 2), '('+StringGrid1.Cells[ACol, ARow-1]+')');
        end;
      end
    else
    begin // Display as text is TryStrToInt failed
      DrawGrid1.Canvas.Font.Name := 'Courier New';
      DrawGrid1.Canvas.Font.Size := 12;
      DrawGrid1.Canvas.Font.Style := [];
      DrawGrid1.Canvas.TextRect(Rect, Rect.Left+CellPadding, Rect.Top+(DrawGrid1.RowHeights[ARow] div 2)-(DrawGrid1.Canvas.TextHeight('Ag') div 2), StringGrid1.Cells[ACol, ARow-1]);
    end;
    end
    else
    begin // All other columns display as text
      DrawGrid1.Canvas.Font.Name := 'Courier New';
      DrawGrid1.Canvas.Font.Size := 12;
      DrawGrid1.Canvas.Font.Style := [];
      DrawGrid1.Canvas.TextRect(Rect, Rect.Left+CellPadding, Rect.Top+(DrawGrid1.RowHeights[ARow] div 2)-(DrawGrid1.Canvas.TextHeight('Ag') div 2), StringGrid1.Cells[ACol, ARow-1]);
    end;
  end;
end;

【问题讨论】:

  • 欢迎来到stackoverflow。请,你能提供一些你的具体问题的代码。这证明了您尝试了多远,它将帮助其他成员更好地理解您的问题,当时,您将向他们提供您的问题的背景。请检查以下链接:stackoverflow.com/help/mcvestackoverflow.com/help/how-to-ask
  • 这是给德尔福的吗?如果是这样,我们可能应该这样标记它
  • Delphi,XE8,但适用于任何版本的解决方案也可以!
  • 你试过TGraphic.Draw
  • 您走错了路,返回将它们加载到图像列表并按照评论使用“绘图”。除了 'AlphaBlend' GDI 会忽略 alpha 通道,'CopyRect' 将不起作用。

标签: delphi canvas png


【解决方案1】:

更新 - 我自己解决了。我又看了看我第一次尝试的 Draw 方法(因为它们出现在错误的位置而放弃了),并意识到我弄乱了 X+Y。这是清理后的代码。我相信它可以简化一点。我还在玩,看看如何制作一个漂亮的 DrawGrid。 Here's a screen grab of the result.

procedure TLottoResults.DrawGrid1DrawCell(Sender: TObject; ACol, ARow: Integer; Rect: TRect; State: TGridDrawState);
var
  dcBall: Integer;
begin
  DrawGrid1.Canvas.Brush.Style := bsClear;
  if ARow = 0 then
  begin
    DrawGrid1.Canvas.Font.Name := 'Tahoma';
    DrawGrid1.Canvas.Font.Size := 12;
    DrawGrid1.Canvas.Font.Style := [fsBold];
    DrawGrid1.Canvas.TextRect(Rect, Rect.Left+CellPadding, Rect.Top, Colnames[ACol])
  end
  else
  begin
    if gdSelected in State then DrawGrid1.Canvas.Brush.Color := clGreen
    else DrawGrid1.Canvas.Brush.Color := clNavy;
    DrawGrid1.Canvas.FillRect(Rect);
    DrawGrid1.Canvas.Font.Color := clWhite;
    if ACol in [5..11] then  // columns to display images instead of text
    begin
      // StringGrid1 is what the raw CSV data is loaded into first and is kept invisible,
      // and it's contents are copied to DrawGrid1 for actual display.
      if TryStrToInt(StringGrid1.Cells[ACol, ARow-1], dcBall)then
      begin
        if dcBall in [1..59] then
        begin
          if DataLoaded then
             DrawGrid1.Canvas.Draw(Rect.Left+2,Rect.Top+2,Balls[dcBall].Picture.Graphic); 
        end
        else
        begin // Display as text if not in range 1 to 59
          DrawGrid1.Canvas.Font.Name := 'Courier New';
          DrawGrid1.Canvas.Font.Size := 12;
          DrawGrid1.Canvas.Font.Style := [];
          DrawGrid1.Canvas.TextRect(Rect, Rect.Left+CellPadding, Rect.Top+(DrawGrid1.RowHeights[ARow] div 2)-(DrawGrid1.Canvas.TextHeight('Ag') div 2), '('+StringGrid1.Cells[ACol, ARow-1]+')');
        end;
      end
      else
      begin // Display as text is TryStrToInt failed
        DrawGrid1.Canvas.Font.Name := 'Courier New';
        DrawGrid1.Canvas.Font.Size := 12;
        DrawGrid1.Canvas.Font.Style := [];
        DrawGrid1.Canvas.TextRect(Rect, Rect.Left+CellPadding, Rect.Top+(DrawGrid1.RowHeights[ARow] div 2)-(DrawGrid1.Canvas.TextHeight('Ag') div 2), StringGrid1.Cells[ACol, ARow-1]);
      end;
    end
    else
    begin // All other columns display as text
      DrawGrid1.Canvas.Font.Name := 'Courier New';
      DrawGrid1.Canvas.Font.Size := 12;
      DrawGrid1.Canvas.Font.Style := [];
      DrawGrid1.Canvas.TextRect(Rect, Rect.Left+CellPadding, Rect.Top+(DrawGrid1.RowHeights[ARow] div 2)-(DrawGrid1.Canvas.TextHeight('Ag') div 2), StringGrid1.Cells[ACol, ARow-1]);
    end;
  end;
end;

【讨论】:

    猜你喜欢
    • 2018-03-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-09-03
    • 2014-11-22
    • 2019-10-19
    • 1970-01-01
    • 2023-03-11
    相关资源
    最近更新 更多