0
votes

I want to add transparent and partly transparent regions on a Image.Bitmap. I found out, that the transparency regions does not affect as expected: The RGB parts of the TAlphaColor value does affect more than they should - so it is e.g. not possible to build a clean transparency gradient.

To show this I buildt this small example: If I set the alpha value of a TAlphaColor value to "0", the pixel should be fully transparent - independend of the other RGB values of the value.

Delphi does not behave as expected: Even if set the Alpha Value to "0", the foreground bitmap is not fully transparent. (If I set the whole TAlphaColor to $00000000 it is fully transparent - but this is not what I want)

Full Source Code:

Form, pas code:

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.

Form, fmx code:

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

Project code, dpr:

program TestAlpha;

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

{$R *.res}

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

Screenshot of the running programm: The pink rectangle has alpha value of "0" - but still is not fully transparent.

enter image description here

Working on Delphi XE6, FMX, Win32.

2
I have the opposite problem in XE7, My opacity is set to 1 yet can still see through everything.Jerry Dodge
The problem has to do with premultiplied alpha, see Alpha_compositing xCl := xBitmapData.GetPixel(iX,iY); xCl := UnpremultiplyAlpha(xCl); TAlphaColorRec(xCl).A := 0; xCl := PremultiplyAlpha(xCl); xBitmapData.SetPixel(iX,iY,xCl); will solve the problem in this example - but not the problem in general: When changing the transparency of a pixel, the color information is lost.BitBumper

2 Answers

0
votes

As in my comment above: The problem has to do with premultiplied alpha mode in Delphi.

If you need to remember color information about transparent areas a copy of the bitmap is mandatory to be able to access the orginal color information.

If some transparent areas should be joined, the minimum of transparency will solve the problem:

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);
0
votes

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

You get intermediate opacity by setting the last parameter (AOpacity) to something between 0 and 1. Try ...

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