Hm, jetzt hab' ich das schon mit LazIntfImg gemacht. Dauert jetzt zum Filtern ca. 4 Sekunden und mit weichen Rändern ca. 10 Sekunden.
Jetzt sieht meine Funktion so aus:
Code: Alles auswählen
function Blaufilter(Bild : TBitmap; Farbe,Filter : TFPColor; _Abweichung : Byte; Schaerfe : byte) : TBitmap;
var
Pic1,Pic2 : TLazIntFImage;
x,y : integer;
a,b,c,d,e,f : smallint;
i : word;
s : single;
t : single;
Pix : TFPColor;
Bit,Mask : HBitmap;
Abweichung : Cardinal;
procedure _IsPixInFilter;
begin
if (Power(abs(Pix.Red - Filter.Red),1.4) < Abweichung)
and (Power(abs(Pix.Green - Filter.Green),1.4) < Abweichung)
and (Power(abs(Pix.Blue - Filter.Blue),1.4) < Abweichung) then Pix := Farbe;
end;
begin
Operating := true;
Abweichung := _Abweichung * 21703;
if (Farbe.Alpha > 64770) then Farbe.Alpha := 64770;
Result := TBitmap.Create;
Pic1 := TLazIntFImage.Create(0,0);
Pic1.LoadFromBitmap(Bild.Handle,Bild.MaskHandle);
Pic2 := TLazIntFImage.Create(Bild.Width,Bild.Height);
Pic2.LoadFromBitmap(Bild.Handle,Bild.MaskHandle);
Form1.ProgressBar1.Position := 10;
for y := 0 to Bild.Height - 1 do begin
for x := 0 to Bild.Width - 1 do begin
Pix := Pic1.Colors[x,y];
_IsPixInFilter;
Pic2.Colors[x,y] := Pix;
end;
if (Bild.Width > 2) then Form1.ProgressBar1.Position :=
Round((y + 1) / (Bild.Height) * 60 + 10);
Application.ProcessMessages;
if (not Operating) then begin Pic1.Free; Pic2.Free; exit; end;
end;
if (Schaerfe > 0) then for y := 0 to Bild.Height - 1 do begin
x := 0;
a := y - Schaerfe;
if (a < 0) then a := 0;
b := y + Schaerfe;
if (b >= Bild.Height) then b := Bild.Height - 1;
c := x - Schaerfe;
if (c < 0) then c := 0;
d := x + Schaerfe;
if (d >= Bild.Width) then d := Bild.Width - 1;
i := 0;
for e := a to b do for f := c to d do if (Pic2.Colors[f,e].alpha <> 65535)
then inc(i);
for x := 0 to Bild.Width - 1 do begin
c := x - Schaerfe;
if (c < 0) then c := 0;
d := x + Schaerfe;
if (d >= Bild.Width) then d := Bild.Width - 1;
if (c > 0) then for e := a to b do if (Pic2.Colors[c - 1,e].Alpha <> 65535)
then dec(i);
if (x + Schaerfe < Bild.Width) then for e := a to b do if
(Pic2.Colors[d,e].Alpha <> 65535) then inc(i);
pix := Pic2.Colors[x,y];
s := i / (Schaerfe * Schaerfe * 4);
Pix.Red := Round(Pix.Red * (1-s) + Farbe.Red * s);
Pix.Green := Round(Pix.Green * (1-s) + Farbe.Green * s);
Pix.Blue := Round(Pix.Blue * (1-s) + Farbe.Blue * s);
Pic2.Colors[x,y] := Pix;
end;
if (Bild.Width > 2) then Form1.ProgressBar1.Position :=
Round((y + 1) / (Bild.Height) * 117 + 70);
Application.ProcessMessages;
if (not Operating) then begin Pic1.Free; Pic2.Free; exit; end;
end;
Pic2.CreateBitmaps(Bit,Mask,false);
Form1.ProgressBar1.Position := 190;
Result.Handle := Bit;
Form1.ProgressBar1.Position := 193;
Result.MaskHandle := Mask;
Form1.ProgressBar1.Position := 196;
Pic1.Free;
Pic2.Free;
Form1.ProgressBar1.Position := 198;
Operating := false;
end;
Hier kann man jetzt auch den Alpha-Wert einstellen. Canvas kann also doch Alphablending. Der "übermahlte" Bereich ist jetzt immer leicht transparent (254), um einen weichen Übergang zu ermöglichen, ohne jedes Mahl _IsPixInFilter aufrufen zu müssen.
[EDIT] Wenn das Programm während dem Bearbeiten geschlossen wird, muss man in Form.OnClose noch die globale Variable Operating auf false setzten und danach noch ein Application.Processmessages einbauen, damit das Filtern ohne Fehler abgebrochen wird.
Ich denke, es lohnt sich, doch noch was mit Scanline zu machen. Ich schreib' dann nochmal, wenn's fertig ist.