Operacje na bitmapie - półprzezroczystość
dziadek Prokop
Nie potrafie się rozpisywać bo małorolny jestem i głowy do poezji nie mam :) więc przedstawiam kod który opisałem krok po kroku.
Być może sie komuś przyda i zrobi z niego fajny komponent.
Dopiero po wielu latach udało mi się wreszcie poprawnie zarejestrować na tej witrynce :) (dawny Inter) - więc to moja pierwsza tu spuścizna, dlatego prosze o wyrozumiałość :)
UNIT modBitmap;
INTERFACE
Uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ExtCtrls;
type Error = class(Exception);
//Funkcja pobiera rozmiar pixela
FUNCTION GetPixelSize(bitmap:TBITMAP):INTEGER;
//Procedura rozkłada kolor na składowe RGB
PROCEDURE GetRGB(col:TCOLOR; var r,g,b:BYTE);
//Funkcja pobiera wspólny kolor pixela z dwu podanych kolorów
FUNCTION GetPixFilter(col,colBackground:TCOLOR; Filter:BYTE):TCOLOR;
//Procedura filtruje Bitmapę (półprzezroczystość)
PROCEDURE BitmapFilter(pozX,pozY:INTEGER; bitmapSrc,bitmapTlo:TBITMAP; Filter:BYTE);
//Procedura kreuje pusty region dla Bitmapy
PROCEDURE BitmapRegion(TransparentColor:TCOLOR; Bitmap:TBITMAP; Form:TFORM);
VAR
BitmapDST :TBitmap;
PixelFormat :Byte;
{*********************************************************}
IMPLEMENTATION
const BitsPerByte = 8;
{=========== Funkcja pobiera rozmiar pixela ============}
FUNCTION GetPixelSize(bitmap:TBITMAP):INTEGER;
var
BitCount,Multiplier :INTEGER;
Begin
case bitmap.PixelFormat of pfDevice:
begin
BitCount:= GetDeviceCaps(bitmap.Canvas.Handle, BITSPIXEL);
Multiplier:= BitCount div BitsPerByte;
if (BitCount mod BitsPerBYTE) > 0 then
begin
Inc(Multiplier);
end;
end;
pf1bit: Multiplier := 1;
pf4bit: Multiplier := 1;
pf8bit: Multiplier := 1;
pf15bit: Multiplier := 2;
pf16bit: Multiplier := 2;
pf24bit: Multiplier := 3;
pf32bit: Multiplier := 4;
else raise Error.Create('Bitmapa nieznany format pixela !');
end;
Result:=Multiplier;
End;
{========= Procedura rozkłada kolor na składowe RGB =======}
PROCEDURE GetRGB(col:TCOLOR; var r,g,b:BYTE);
Begin
R:= GetRValue(col);
G:= GetGValue(col);
B:= GetBValue(col);
End;
{= Funkcja pobiera wspólny kolor pixela z dwu podanych kolorów ===}
FUNCTION GetPixFilter(col,colBackground:TCOLOR; Filter:BYTE):TCOLOR;
var
r,g,b,r2,g2,b2 :BYTE;
Begin
//rozkład koloru pixela pobranego z obrazka
GetRGB(col, r,g,b);
//rozkład koloru pixela z podanego tła obrazka
GetRGB(colBackground, r2,g2,b2);
//ustalenie średniej koloru w odpowiednim zestawieniu %
R:= (r * Filter div 255) + (r2-r2 * Filter div 255);
G:= (g * Filter div 255) + (g2-g2 * Filter div 255);
B:= (b * Filter div 255) +( b2-b2 * Filter div 255);
Result:=RGB(R, G, B);
End;
{=== Procedura filtruje Bitmapę (półprzezroczystość) =========}
PROCEDURE BitmapFilter(pozX,pozY:INTEGER; bitmapSrc,bitmapTlo:TBITMAP; Filter:BYTE);
var
kl,ln,gps :INTEGER;
P1,P2,P3 :PByteArray;
Begin
//zabezpieczenia przed uwagami błędów kompilacji...
P1:=nil; P2:=nil; P3:=nil;
if Filter < 1 then Filter:=0;
if Filter > 254 then Filter:=255;
//ustalenie wielkości bitowych dla bitmap...
bitmapTlo.PixelFormat:=pf24Bit;
if PixelFormat=16 then bitmapTlo.PixelFormat:=pf16Bit;
if PixelFormat=24 then bitmapTlo.PixelFormat:=pf24Bit;
if PixelFormat=32 then bitmapTlo.PixelFormat:=pf32Bit;
bitmapSrc.PixelFormat:=bitmapTlo.PixelFormat;
BitmapDst.PixelFormat:=bitmapTlo.PixelFormat;
gps:=GetPixelSize(bitmapTlo); //rozmiar pixela dla bitmapy
//przepisanie zawartości bitmap
BitmapDst.Assign(bitmapSrc);
for ln:=0 to BitmapDst.Height-1 do
begin
try
P1:=bitmapSrc.ScanLine[ln]; //skan linii z bitmapy żródłowej
P2:=bitmapTlo.ScanLine[ln+pozY]; //skan linii z bitmapy tła
P3:=BitmapDst.ScanLine[ln]; //skan linii dla bitmapy docelowej
except
end;
kl:=0;
repeat
//jeżeli ustawiona opcja wyświetlania jako duszka to...
if BitmapDst.Transparent then
//...podmienia kolor zerowy na kolor z bitmapTlo
if P1[kl]=0 then P3[kl]:=P2[kl+pozX * gps];
//ustawia wartość pośrednią dla pixeli z bitmapDst i bitmapTlo
P3[kl]:=GetPixFilter(P3[kl],P2[kl+pozX * gps],Filter);
Inc(kl);
until kl > bitmapDst.Width * gps;
end;
bitmapTlo.Canvas.Draw(pozX,pozY,BitmapDst); //przerysowanie do bitmapy tła
End;
{======= Procedura kreuje pusty region dla Bitmapy =========}
PROCEDURE BitmapRegion(TransparentColor:TCOLOR; Bitmap:TBITMAP; Form:TFORM);
//funkcja kreująca region (wewnętrzna część procedury)
Function KreujRegion(Bitmap:TBITMAP; KolorTla:TCOLOR):HRGN;
var
x,y,startX,endX,wd :Integer;
rgn2 :HRGN;
Begin
Result:= CreateRectRgn(0,0,0,0);
for y:=0 to Bitmap.Height-1 do
begin
x:=0; wd:=Bitmap.Width;
while x < wd do
begin
while (Bitmap.Canvas.Pixels[x,y]= KolorTla) and (x <= wd) do inc(x);
startX:=x; inc(x);
while (Bitmap.Canvas.Pixels[x,y]<> KolorTla) and (x <= wd) do inc(x);
endX:=x;
if startX < wd then
begin
rgn2:=CreateRectRgn(startX+1,y,endX,y+1);
if rgn2 <> 0 then CombineRgn (Result, Result,rgn2, RGN_OR);
DeleteObject(rgn2);
end;
end;
end;
End;
//główna część procedury...
Begin
SetWindowRgn(Form.Handle, KreujRegion(Bitmap,TransparentColor), True);
End;
{------- Instrukcje do wykonania podczas załadowania modułu --------}
INITIALIZATION
bitmapDst:= TBitmap.Create; //wykreowanie bitmapy obrazka po "sfiltrowaniu"
{---- Instrukcje do wykonania podczas zakończenia pracy modułu ----}
FINALIZATION
bitmapDst.Free //zwolnienie bitmapy obrazka po "sfiltrowaniu"
END.
PRAKTYCZNE ZASOSOWANIE W PROGRAMIE
UNIT BitmapaOperacjeForm;
INTERFACE
Uses
modBitmap, //moduł zawiera procedury do obsługi Bitmap
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ExtCtrls, StdCtrls, ComCtrls;
Type
TForm1 = class(TForm)
Image1: TImage;
ramkaGroupBox1: TGroupBox;
Label1: TLabel;
Label2: TLabel;
Edit1: TEdit;
Edit2: TEdit;
ScrollBar1: TScrollBar;
ScrollBar2: TScrollBar;
PROCEDURE FormCreate(Sender: TObject);
PROCEDURE ScrollBar1Change(Sender: TObject);
PROCEDURE ScrollBar2Change(Sender: TObject);
Private
PROCEDURE Pokazuj; //Pokazywanie obrazków
Public
{Public declarations}
End;
VAR
Form1 :TForm1;
obrazek1,obrazek2,obrazekTlo :TBitmap;
{********************************************************}
IMPLEMENTATION {$R *.DFM}
PROCEDURE TForm1.FormCreate(Sender: TObject);
Begin
//wykreowanie zmiennych bitmap...
Obrazek1:= TBitmap.Create;
Obrazek2:= TBitmap.Create;
ObrazekTlo:= TBitmap.Create;
//wczytanie obrazków do zmiennych bitmap
Obrazek1.LoadFromFile('Obrazek1.bmp');
Obrazek2.LoadFromFile('Obrazek2.bmp');
ObrazekTlo.LoadFromFile('ObrazekTło.bmp');
//wywołanie procedury pokazywania obrazków
Pokazuj;
End;
{=========== Pokazywanie obrazków =================}
PROCEDURE TForm1.Pokazuj;
var
obrazekTmp :TBitmap;
Filtr1,Filtr2 :Byte;
Begin
obrazekTmp:=TBitmap.Create; //wykreowanie zmiennej obrazka tymczasowego
obrazekTmp.Assign(ObrazekTlo); //przepisanie zawartości z obrazka tła
//ustawianie wielkości filtra (0-255)
Filtr1:=ScrollBar1.Position;
Filtr2:=ScrollBar2.Position;
//ustawienie opcji wyświetlania jako duszka...
Obrazek1.Transparent:=true;
Obrazek2.Transparent:=true;
//filtrowanie obrazków
BitmapFilter(10,10,obrazek1,ObrazekTmp,Filtr1);
BitmapFilter(50,30,obrazek2,ObrazekTmp,Filtr2);
//narysowanie tła zawierającego obrazki "półprzezroczyste"
Image1.Canvas.Draw(0,0,ObrazekTmp);
{używając poniższego rysujesz półprzezroczyte bitmapy na pulpicie
ObrazekTlo.canvas.handle:=GetWindowDC(GetDesktopWindow); }
End;
{============= Pobieranie danych filtrów ==============}
{----------- Ustawianie filtra1 za pomocą ScrollBar1 ---------------------}
PROCEDURE TForm1.ScrollBar1Change(Sender: TObject);
Begin
Edit1.Text:=IntToStr(ScrollBar1.Position);
Pokazuj;
End;
{----------- Ustawianie filtra2 za pomocą ScrollBar2 ---------------------}
PROCEDURE TForm1.ScrollBar2Change(Sender: TObject);
Begin
Edit2.Text:=IntToStr(ScrollBar2.Position);
Pokazuj;
End;
END.
Zakres filtrowania 0-255 więc po wrzuceniu na formę TScrollBar ustaw
opcje Max = 255
//Ps. w module dodatkowo zawarta jest procka. dotycząca regionu -
też można by ją zastosować - chociaż w tym przykładzie jest zbędna
to jest szybsze Funkcja Canvas.Draw ze stopniem przeźroczystości bitmapy i obsługą przeźroczystego koloru
Zaje****ą masz gębę!!
_ _
/ \
(0)|(0)
(____)
Pewnie ze sie przyda:)
Właśnie widziałem te dwa arty - dlatego wpadłem na pomysł by ten temat poruszyć.
Co do pierwszego linku - to jest tylko podany rozkład koloru.
A co do drugiego linku - jest to przykład w PHP więc myśle że w Delphi też sie przyda :)
a tego kodu nie próbowałeś?
http://4programmers.net/faq.php?id=718 ??
też powoduje półprzezroczystość danych bitmap. Jeżeli chcesz mieć bardziej przezroczysty rysunek możesz np. umieścić jedną bitmapę czystą. Wyniki graficznie są podobne jak przy:
http://4programmers.net/faq.php?id=717
Tag <d e="e" l="l" p="p" h="h" i="i">! Kod będzie wtedy bardziej czytelny.