To pytanie jest związane z moim earlier question na SO.Alphablend i TransparentBlt
Chcę połączyć dwie warstwy z alfa zastosowane tylko do określonej części warstwy źródłowej. Jednym ze sposobów, w jaki próbowałem, było ustawienie SourceConstantAlpha na $ ff (i funkcja ta używa kanału alfa w warstwie źródłowej).
Ten rodzaj prac - choć powolny (myślę, że mogę go przyspieszyć za pomocą ScanLines), część jest taka, że nie wiem, w jaki sposób ustawić kanał alfa. Dokumentacja sugeruje, że wyliczenie to:
st.Red = Src.Red + (1 - Src.Alpha) * Dst.Red
Próbowałem kilka różnych wartości przez zgadywanie, ale moje pierwsze pytanie brzmi: W jaki sposób obliczyć wartość alfa?
Po przeczytaniu kilku innych pytań dotyczących SO, natknąłem się na funkcję TransparentBlt, która wykonuje maskę dobrze (i szybko), ale nie przezroczystość, czy istnieje sposób połączenia tych dwóch połączeń razem (może za pomocą trzeciej warstwy)?
unit MainWnd;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ExtCtrls, ControlsEx;
type
{------------------------------------------------------------------------------}
TfrmMain = class(TForm)
PaintBox1: TPaintBox;
procedure PaintBox1Paint(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
frmMain: TfrmMain;
implementation
{$R *.dfm}
{..............................................................................}
procedure copyToAlpha(const in_bitmap : TBitmap; const in_transparentColor : TColor;
const in_transparency : integer);
var
x : integer;
y : integer;
p : integer;
begin
ASSERT(in_bitmap.PixelFormat = pf32bit);
for x := 0 to in_bitmap.Width - 1 do
begin
for y := 0 to in_bitmap.Height - 1 do
begin
p := in_bitmap.Canvas.Pixels[x, y];
if TColor(p) <> in_transparentColor then
begin
in_bitmap.Canvas.Pixels[x, y] := p or (in_transparency shl 24);
end
else
in_bitmap.Canvas.Pixels[x, y] := p or ($ff shl 24);
end;
end;
end;
{..............................................................................}
procedure alphaBlendTest(
const in_target : TCanvas;
const in_width : integer;
const in_height : integer);
const
BARSIZE = 30;
var
bitmap : TBitmap;
r : TRect;
blendFn : BLENDFUNCTION;
ret : Boolean;
begin
blendFn.BlendOp := AC_SRC_OVER;
blendFn.SourceConstantAlpha := $ff;
blendFn.BlendFlags := 0;
blendFn.alphaFormat := AC_SRC_ALPHA;
bitmap := TBitmap.Create;
try
bitmap.Width := in_width;
bitmap.Height := in_height;
bitmap.PixelFormat := pf32bit;
bitmap.HandleType := bmDIB;
bitmap.TransparentColor := clFuchsia;
bitmap.Transparent := true;
bitmap.Canvas.Brush.Color := clFuchsia;
bitmap.Canvas.FillRect(Bounds(0, 0, in_width, in_height));
bitmap.Canvas.Brush.Color := clGreen;
r := Bounds(
in_width div 2 - (in_width div 3) div 2,
0,
(in_width div 3) + 1,
BARSIZE + 1);
bitmap.Canvas.Rectangle(r);
// done drawing
//copyToAlpha(bitmap, clFuchsia, 1);
ret := Windows.TransparentBlt(
in_target.Handle,
0,
0,
in_width,
in_height,
bitmap.Canvas.Handle,
0,
0,
in_width,
in_height,
clFuchsia);
//blendFn);
ASSERT(ret);
finally
bitmap.Free;
end;
end;
{..............................................................................}
procedure TfrmMain.PaintBox1Paint(Sender: TObject);
var
r: TRect;
begin
PaintBox1.Canvas.Brush.Color := clBlue;
r := Bounds(0, 0, PaintBox1.ClientWidth, PaintBox1.ClientHeight);
PaintBox1.Canvas.FillRect(r);
PaintBox1.Canvas.Brush.Color := clRed;
PaintBox1.Canvas.Ellipse(0, 0, PaintBox1.ClientWidth, PaintBox1.ClientHeight);
alphaBlendTest(PaintBox1.Canvas, PaintBox1.ClientWidth, PaintBox1.ClientHeight);
end;
end.
Mnożysz y r, g, b każdego piksela r z pożądaną alfą i dzielą przez 255 dla 'AlphaBlend', oczywiście również ustaw alfa piksela na wartość alfa. Nie rozumiem pytania na temat 'TransparentBlt', w jaki sposób przejrzystość nie jest dobra? –
@Sertac OP ma bitmapę, która częściowo składa się z przezroczystego koloru. Przezroczyste części mają pozostać nienaruszone na płótnie docelowym, narysowane części mają być alfablended do płótna docelowego. – NGLN