【问题标题】:Delphi FMX Canvas Alpha Channel give wrong transparencyDelphi FMX Canvas Alpha 通道给出错误的透明度
【发布时间】:2015-02-27 00:14:57
【问题描述】:

我想在 Image.Bitmap 上添加透明和部分透明的区域。 我发现,透明度区域不会像预期的那样影响: TAlphaColor 值的 RGB 部分的影响确实超出了它们应有的程度 - 所以它是例如不可能建立一个 干净的透明度渐变。

为了展示这一点,我构建了这个小例子: 如果我将 TAlphaColor 值的 alpha 值设置为“0”,则像素应该是完全透明的 - 独立于该值的其他 RGB 值。

Delphi 的行为不符合预期: 即使将 Alpha 值设置为“0”,前景位图也不是完全透明的。 (如果我将整个 TAlphaColor 设置为 $00000000 它是完全透明的 - 但这不是我想要的)

完整源代码:

表格,密码:

unit Main;

interface

uses
  System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants, 
  FMX.Types, FMX.Graphics, FMX.Controls, FMX.Forms, FMX.Dialogs, FMX.StdCtrls, FMX.Objects;

type
  TfmMain = class(TForm)
    imgBack: TImage;
    imgFront: TImage;
    procedure FormCreate(Sender: TObject);
  private
  public
  end;

var
  fmMain: TfmMain;

implementation

{$R *.fmx}

procedure ImgInitP(xImg:TImage; xCl:TAlphaColor);
var
  xCorners: TCorners;
begin
  xImg.Bitmap := TBitmap.Create;
  xImg.Bitmap.SetSize(Round(xImg.Width), Round(xImg.Height));
  xImg.Bitmap.Canvas.Fill.Color := xCl;
  xImg.Bitmap.Canvas.BeginScene;
  try
    xImg.Bitmap.Canvas.FillRect(TRectF.Create(xImg.ClipRect),0,0,xCorners,1);
  finally
    xImg.Bitmap.Canvas.EndScene;
  end;
end;

procedure TfmMain.FormCreate(Sender: TObject);
var
  iX: Integer;
  iY: Integer;
  xBitmapData: TBitmapData;
  xCl: TAlphaColor;
begin
  // init 2 images
  ImgInitP(imgBack,$ffbb2211);
  ImgInitP(imgFront,$ff2233dd);
  // set some pixels transparent in foreground picture
  if imgFront.Bitmap.Map(TMapAccess.ReadWrite,xBitmapData) then begin
    try
      for iX := 10 to 30 do begin
        for iY := 10 to 20 do begin
          // set alpha channel of this pixels to zero
          xCl := xBitmapData.GetPixel(iX,iY);
          TAlphaColorRec(xCl).A := 0;
          xBitmapData.SetPixel(iX,iY,xCl);
        end;
      end;
    finally
      imgFront.Bitmap.Unmap(xBitmapData);
    end;
  end;
end;

end.

表格,fmx代码:

object fmMain: TfmMain
  Left = 0
  Top = 0
  Caption = 'Main'
  ClientHeight = 116
  ClientWidth = 248
  FormFactor.Width = 320
  FormFactor.Height = 480
  FormFactor.Devices = [Desktop, iPhone, iPad]
  OnCreate = FormCreate
  DesignerMobile = False
  DesignerWidth = 0
  DesignerHeight = 0
  DesignerDeviceName = ''
  DesignerOrientation = 0
  DesignerOSVersion = ''
  object imgBack: TImage
    MultiResBitmap = <
      item
      end>
    Height = 73.000000000000000000
    Position.X = 8.000000000000000000
    Position.Y = 8.000000000000000000
    Width = 89.000000000000000000
  end
  object imgFront: TImage
    MultiResBitmap = <
      item
      end>
    Height = 73.000000000000000000
    Position.X = 24.000000000000000000
    Position.Y = 24.000000000000000000
    Width = 89.000000000000000000
  end
end

项目代码,dpr:

program TestAlpha;

uses
  FMX.Forms,
  Main in 'Main.pas' {fmMain};

{$R *.res}

begin
  Application.Initialize;
  Application.CreateForm(TfmMain, fmMain);
  Application.Run;
end.

正在运行的程序的屏幕截图: 粉红色矩形的 alpha 值为“0” - 但仍不完全透明。

在 Delphi XE6、FMX、Win32 上工作。

【问题讨论】:

  • 我在 XE7 中遇到了相反的问题,我的不透明度设置为 1,但仍然可以看穿一切。
  • 问题与预乘 alpha 有关,请参阅 Alpha_compositing xCl := xBitmapData.GetPixel(iX,iY); xCl := UnpremultiplyAlpha(xCl); TAlphaColorRec(xCl).A := 0; xCl := PremultiplyAlpha(xCl); xBitmapData.SetPixel(iX,iY,xCl); 将解决此示例中的问题 - 但不是一般问题:当更改像素的透明度时,颜色信息丢失了。

标签: delphi canvas firemonkey alpha delphi-xe6


【解决方案1】:

正如我上面的评论:问题与 Delphi 中的预乘 alpha 模式有关。

如果您需要记住有关透明区域的颜色信息,则必须使用位图的副本才能访问原始颜色信息。

如果要加入一些透明区域,最小的透明度就可以解决问题:

var
  bNewAlpha: byte;
  bOldAlpha: byte;
begin
 // input parameter of new alpha 
 bNewAlpha := 123;
 //
 xCl := xBitmapData.GetPixel(iX,iY);
 xCl := UnpremultiplyAlpha(xCl);
 bOldAlpha := TAlphaColorRec(xCl).A;
 bNewAlpha := Min(bNewAlpha,bOldAlpha);  
 TAlphaColorRec(xCl).A := bNewAlpha;
 xCl := PremultiplyAlpha(xCl);
 xBitmapData.SetPixel(iX,iY,xCl);

【讨论】:

    【解决方案2】:

    xImg.Bitmap.Canvas.FillRect(TRectF.Create(xImg.ClipRect),0,0,xCorners,1);

    您可以通过将最后一个参数 (AOpacity) 设置为 0 到 1 之间的值来获得中间不透明度。试试...

    xImg.Bitmap.Canvas.FillRect(TRectF.Create(xImg.ClipRect),0,0,xCorners,0.5);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-01-02
      • 2010-12-30
      • 1970-01-01
      • 1970-01-01
      • 2013-11-13
      • 2010-10-25
      • 1970-01-01
      • 2012-12-24
      相关资源
      最近更新 更多