需要弄清楚哪些像素是(完全)透明的

Posted

技术标签:

【中文标题】需要弄清楚哪些像素是(完全)透明的【英文标题】:Need to figure which pixels are (completely) transparent 【发布时间】:2012-03-19 09:40:42 【问题描述】:

给定一个包含一些 TGraphic 后代的 Delphi TPicture,我需要计算像素颜色和不透明度。 我想我必须为每个类有不同的实现,而且我想我已经涵盖了 TPngImage。是否支持 32 位位图的透明度? 我可以用比以下更一般的方式解决这个问题吗?:

procedure GetPixelColorAndTransparency(const Picture: TPicture; X, Y:
    Integer; out Color: TColor; out Opacity: Byte);
var
  Bmp: TBitmap;
begin
  if Picture.Graphic is TPngImage then
  begin
    Opacity := (TPngImage(Picture.Graphic).AlphaScanline[Y]^)[X];
    Color := TPngImage(Picture.Graphic).Pixels[ X, Y ];
  end
  else
  if Picture.Graphic is TBitmap then
  begin
    Color := Picture.Bitmap.Canvas.Pixels[ X, Y ];
    Opacity := 255;
  end
  else
  begin
    Bmp := TBitmap.Create;
    try
      Bmp.Assign(Picture.Graphic);
      Color := Bmp.Canvas.Pixels[ X, Y ];
      Opacity := 255;
    finally
      Bmp.Free;
    end;
  end;
end;

【问题讨论】:

不存在真正的一般情况,因为并非所有 TGraphic 后代都支持部分 (>1bit) 透明度。 是的,32 位位图有一个 Alpha 通道。请参阅下面的答案。 【参考方案1】:

这样的事情怎么样:

procedure GetPixelColorAndTransparency(const Picture: TPicture; X, Y: Integer; out Color: TColor; out Opacity: Byte); 
type
  PRGBQuadArray = ^TRGBQuadArray;
  TRGBQuadArray = array [Integer] of TRGBQuad;
var 
  Bmp: TBitmap; 
begin 
  if Picture.Graphic is TPngImage then 
  begin 
    with TPngImage(Picture.Graphic) do begin
      Opacity := AlphaScanline[Y]^[X]; 
      Color := Pixels[X, Y]; 
    end;
  end 
  else if Picture.Graphic is TBitmap then 
  begin 
    with Picture.Bitmap do begin
      Color := Canvas.Pixels[X, Y]; 
      if PixelFormat = pf32Bit then begin
        Opacity := PRGBQuadArray(Scanline[Y])^[X].rgbReserved;
      end
      else if Color = TranparentColor then begin
        Opacity := 0;
      end
      else begin
        Opacity := 255; 
      end;
    end;
  end else 
  begin 
    Bmp := TBitmap.Create; 
    try 
      Bmp.Assign(Picture.Graphic); 
      Color := Bmp.Canvas.Pixels[X, Y]; 
      if Color = Bmp.TranparentColor then begin
        Opacity := 0;
      end else begin
        Opacity := 255; 
      end;
    finally 
      Bmp.Free; 
    end; 
  end; 
end; 

【讨论】:

很好的答案,恰到好处。很抱歉延迟回答。【参考方案2】:

未优化但简单易懂:

procedure GetPixelColorAndTransparency(const Picture: TPicture; X, Y:
    Integer; out Color: TColor; out Opacity: Byte);
var
  Bmp: TBitmap;
  Color32: Cardinal;
begin
  Bmp := TBitmap.Create;
  try
    Bmp.Assign(Picture.Graphic);
    Color32 := Bmp.Canvas.Pixels[ X, Y ];
    Color := Color32 and $00FFFFFF;
    Opacity := Color32 shr 24;
  finally
    Bmp.Free;
  end;
end;

【讨论】:

以上是关于需要弄清楚哪些像素是(完全)透明的的主要内容,如果未能解决你的问题,请参考以下文章

Perl GD 检查像素是不是透明

如何在OpenGL中绘制单个像素?

合并两个图像

是什么让这次点击?

渲染具有透明度的纹理时 OpenGL 不需要的像素

裁剪掉透明像素但保留偏移量