Funkcja Canvas.Draw ze stopniem przeźroczystości bitmapy i obsługą przeźroczystego koloru
Piotrekdp
Oto uniwerslna funkcja rysująca grafikę o dowolnym procencie przeźroczystości z możliwością ustawienia przeźroczystego koloru
Dzięki tej procedurze możemy narysować grafikę prześwitującą w podanym procencie zachowując przy tym "normalny" przeźroczysty kolor.
Przykład
Dysponując takim oto rysunkiem :
Po ustawieniu w btmapie koloru przeźroczystego na niebieski
można powyższy obrazek narysować (nawet na pulpicie) tak :
<b>Parametry Procedury DrawTransparency()</b>
*Canvas - Canvas (płótno)Na którym rysujemy bitmapę.
*X,Y - pozycja jak w zwykłym Canvas.Draw().
- Transparency-stopień przeźroczystości -przyjmuje wartości od 0 do 100.
Aby bitmapa była narysowana z uwzględnieniem przeźroczystego koloru "tradycyjnie" ustawiamy :
Bitmapka.TransparentColor=clBlack;
Bitmapka.Transparent:=True;
i wywołujemy procedurę DrawTransparency() z parametrami :)
procedure DrawTransparency(Canvas:TCanvas;X,Y:Integer ;Bitmap:TBitmap;Transparency:Byte);
var
Temp:TBitmap;
ByteSrc,ByteDest:^Byte;
TripleSrc,TripleDest:^TRGBTriple;
TransparentColor:TRGBTriple;
H,V:Integer;
begin
Bitmap.PixelFormat:=pf24bit;
Temp:=TBitmap.Create;
Temp.Canvas.Brush.Color :=Bitmap.TransparentColor; //ustawiam sobie aby bitmapa była odrazu w kolorze przeźroczystym ...
Temp.Width :=Bitmap.Width ; //...niezależnie od tego czy przeżrczystość jest czy jej nie ma
Temp.Height :=Bitmap.Height ;
Temp.PixelFormat:=pf24bit;
Temp.Canvas.CopyRect(Rect(0,0,Bitmap.Width ,Bitmap.Height ),Canvas,Rect(X,Y,Bitmap.Width+X ,Bitmap.Height+Y ));
if Bitmap.Transparent then
//Jak Jest Przeźroczystośc to mamy dużo roboty bo musimy omijać w modyfikacji kolor przeżroczysty
begin
{Zamieniam Kolor Przeżroczysty TColor na TRGBTriple do porównań}
TransparentColor.rgbtBlue :=(Bitmap.TransparentColor and $FF0000) shr 16 ;
TransparentColor.rgbtGreen :=(Bitmap.TransparentColor and $00FF00) shr 8 ;
TransparentColor.rgbtRed :=Bitmap.TransparentColor and $0000FF;
Temp.TransparentColor :=Bitmap.TransparentColor;
Temp.Transparent :=True; //Jak bitmapka jest przeźroczysta to i po przeróbce też
for V:=0 to Bitmap.Height -1 do
begin
TripleSrc:=Bitmap.ScanLine[V];
TripleDest:=Temp.ScanLine[V];
for H:=0 to Bitmap.Width -1 do
begin
if(TransparentColor.rgbtBlue <> TripleSrc.rgbtBlue) or
( TransparentColor.rgbtGreen <> TripleSrc.rgbtGreen) or
(TransparentColor.rgbtRed <> TripleSrc.rgbtRed ) then
begin
TripleDest^.rgbtBlue :=Trunc((TripleDest^.rgbtBlue / 100)*Transparency+
(TripleSrc^.rgbtBlue / 100)*(100-Transparency));
TripleDest^.rgbtGreen :=Trunc((TripleDest^.rgbtGreen / 100)*Transparency+
(TripleSrc^.rgbtGreen / 100)*(100-Transparency));
TripleDest^.rgbtRed :=Trunc((TripleDest^.rgbtRed / 100)*Transparency+
(TripleSrc^.rgbtRed / 100)*(100-Transparency));
end;
inc(TripleSrc);
inc(TripleDest);
end ;
end;
end
else // Gdy nie mamy przeźroczystosci koloru to lecimy po bajtach dlatego osobna wersja bo bez if-ów i szybciej
begin
for V:=0 to Bitmap.Height -1 do
begin
ByteSrc:=Bitmap.ScanLine[V]; // nasza bitmapka
ByteDest:=Temp.ScanLine[V]; // bitmapka reprezetująca "Canvas"
for H:=0 to Bitmap.Width*3 -1 do
begin
ByteDest^:=Trunc((ByteDest^ / 100)*Transparency+ // procent koloru tła
(ByteSrc^ / 100)*(100-Transparency)); // procent koloru Bitmapy
inc(ByteSrc);
inc(ByteDest);
end;
end;
end;
Canvas.Draw(X,Y,Temp); //Rysujemy Bitmapke
Temp.Free;
end;
A czy da się to jakoś przerobić by stworzyć funkcję do kopiowania fragmentu obrazu PNG z przezroczystościami do innej zmiennej z obrazem PNG??
Załóżmy miałbym dwie zmienne przechowujące obrazy: a i b.
Do a wczytuję duży obrazek, a do b mam skopiować tylko jego fragment z zachowaniem przezroczystości.
Coś ala CopyRect() z Canvasu.
Może ktoś podać przykład wywołania tej funkcji z artykułu?
Jeśli obie bitmapy mogą być 32 bitowe i już zawierać informacje o przezroczystości (na przykład dla LayeredWindow), to proponuję taki kod:
Malutkie sprostowanie ww przykładzie napisałem sobie kolor z głowy -clBlack , natomiast wiadomo że jak rysowałem "duszka" ustawiłem clBlue ; :)
a co do samej zasady dzałania kodu jest bardzo prosta ,
Kopiuje kawałeczek tła spod spodu bitmapki i biorę kazdy pixel wyliczając procentowo kolory
jeśli np przeźroczystośc to 20% to wyświetlamy kolor składający się w 80% z koloru "wieszchniego"
i 20% z pod spodu - proste :)
Przydatny art!