Kein "echtes" Antialiasing, aber ein konfigurierbarer 5x5-Blur.
In AntAussen, AnzMitte und AntInnen lässt sich einstellen, wie stark welche Region in den Zielpixel einfliessen soll (wobei AntInnen das Zentrum darstellt). Dabei sollte man beachten, dass die Anteile summiert = 1 sind, sonst wird's unschön.
Die Prozedur dürfte recht fix sein, und sich auch für den einen oder anderen "realtime"-Einsatz eignen (vielleicht nicht ganz fullscreen, aber immerhin
)
Anmerkung: Das ganze ist NICHT als Funktion implementiert, da ich den Eindruck hatte, dass es so schneller läuft.
Anmerkung2: Die Kanten des Bildes werden allerdings vernachlässigt, um nicht noch if-Abfragen rein zu bringen. Das Teil ist auf Geschwindigkeit geschrieben (und dass wo ich doch kein Wort Assembler kann 8) ).
Die Regionen sehen folgendermaßen aus:
A = Aussen (AntAussen)
M = Mitte (AntMitte)
I = Innen (AntInnen)
Delphi-Quellcode:
A A A
A M M M A
A M I M A
A M M M A
A A A
Der Code:
Delphi-Quellcode:
type
PixelA3 =
array[1..3]
of Byte;
PixelA15 =
array[1..15]
of Byte;
procedure TForm1.AntiAlias5(
const i: TBitmap;
var o: TBitmap);
var
Po: ^PixelA3;
P1, P2, P3, P4, P5: ^PixelA15;
x, y: Cardinal;
dekrement: Cardinal;
AntAussen, AntMitte, AntInnen: double;
begin
// Anteile der Regionen am Zielpixel festlegen
AntAussen := 12*4;
// 12 Pixel zu 1/4 in Ziel-Pixel
AntMitte := 8*4;
// 8 Pixel zu 1/4 in Ziel-Pixel
AntInnen := 2;
// 1 Pixel zu 1/2 in Ziel-Pixel
dekrement := 3*(i.Width-3);
// Scanline der ersten 5 Zeilen abholen
P1 := i.ScanLine[0];
P2 := i.ScanLine[1];
P3 := i.ScanLine[2];
P4 := i.ScanLine[3];
P5 := i.ScanLine[4];
for y := 2
to i.Height-4
do
begin
// Scanline des Zielbildes abholen
Po := o.ScanLine[y];
// und die x-Position um 2 erhöhen (wie gesagt, Rand spielt nicht mit)
inc(Po, 2);
for x := 2
to i.Width-2
do
begin
// Blauwert des Zielpixels aus den Blauwerten der Ausgangsregion basteln
Po^[1] := round(((P1^[4]+P1^[7]+P1^[10] +
P2^[1] + P2^[13] +
P3^[1] + P3^[13] +
P4^[1] + P4^[13] +
P5^[4]+P5^[7]+P5^[10]) / AntAussen) +
((P2^[4]+P2^[7]+P2^[10] +
P3^[4] +P3^[10] +
P4^[4]+P4^[7]+P4^[10]) / AntMitte) +
(P3^[7] / AntInnen));
// Wie bei Blau, jetzt mit grün
Po^[2] := round(((P1^[5]+P1^[8]+P1^[11] +
P2^[2] + P2^[14] +
P3^[2] + P3^[14] +
P4^[2] + P4^[14] +
P5^[5]+P5^[8]+P5^[11]) / AntAussen) +
((P2^[5]+P2^[8]+P2^[11] +
P3^[5] +P3^[11] +
P4^[5]+P4^[8]+P4^[11]) / AntMitte) +
(P3^[8] / AntInnen));
// und bei Rot...
Po^[3] := round((( P1^[6]+P1^[9]+P1^[12] +
P2^[3] + P2^[15] +
P3^[3] + P3^[15] +
P4^[3] + P4^[15] +
P5^[6]+P5^[9]+P5^[12]) / AntAussen) +
((P2^[6]+P2^[9]+P2^[12] +
P3^[6] +P3^[12] +
P4^[6]+P4^[9]+P4^[12]) / AntMitte) +
(P3^[9] / AntInnen));
// Alle Zeiger um 3 Byte erhöen - also einen Pixel nach rechts
// (PByte deswegen, weil P1-P5 15 Bytes groß sind, und sonst auch um
// 15 Byte verschoben würden.)
inc(PByte(P1), 3);
inc(PByte(P2), 3);
inc(PByte(P3), 3);
inc(PByte(P4), 3);
inc(PByte(P5), 3);
// Zeiger des Zielpixels einen Pixel nach rechts
inc(Po, 1);
end;
// Alle Zeiger auf den Pixel links ziehen
dec(PByte(P2), dekrement);
dec(PByte(P3), dekrement);
dec(PByte(P4), dekrement);
dec(PByte(P5), dekrement);
// und dann die Zeilen verschieben
P1 := P2;
P2 := P3;
P3 := P4;
P4 := P5;
P5 := i.ScanLine[y+3];
// und die neue Zeile holen
end;
end;
Viel Spaß damit, und wer Fehler findet darf sie behalten --- oder schickt mir besser eine PM. Aber ich hab das Teil erfolgreich im Einsatz
gruss,
dizzy
[edit=Matze]Code formatiert. Mfg, Matze[/edit]
Fabian K.
INSERT INTO HandVonFreundin SELECT * FROM Himmel