Ja, das von der französischen Seite sieht ganz gut aus. Was mit GDI so alles geht...
Ich hab' auch mal eben schnell was geschrieben, aber auf so eine einfache Lösung bin ich nicht gekommen.
Allerdings habe ich es endlich mal mit linearer Interpolation anstatt immer nur mit "Nearest neighbour" umgesetzt. Das wollte ich eh schon immer mal machen. Falls es jemand interessiert (Aber nur für 24bit Bilder!):
PROCEDURE RotateImage24LinearInterpolation(SourceBMP, DestBMP: TBitmap; Degree: double; BackCol : TColor); TYPE
TByteArray = ARRAY[0..655360] OF byte;
pByteArray = ^TByteArray; VAR
X, Y, iX : integer;
RX, RY : integer;
dRX, dRY : double;
SCX, SCY : integer;
DCX, DCY : integer;
W, H : integer; // Width and Height of Source Bitmap
s, c : extended;
fX, fY, d: double;
pDest : pByteArray;
pSource : ARRAYOF pByteArray;
RGBBack : integer;
c11, c12,
c13, c21,
c22, c23 : double; BEGIN IF Degree = 0 then begin
DestBMP.Assign(SourceBMP);
EXIT; end; IF SourceBMP.PixelFormat <> pf24bit then
exit;
RGBBack := BackCol; // Now switch Blue and Red
RGBBack := ((RGBBack and $00FF0000) shr 16) or
((RGBBack and $0000FF00) ) or
((RGBBack and $000000FF) ) shl 16;
W := SourceBMP.Width;
H := SourceBMP.Height;
SCX := W div 2;
SCY := H div 2;
SinCos(Degree*Pi/180, s, c);
// Calculate new size for Destinatio image
DestBMP.PixelFormat := pf24bit;
DestBMP.Height := round(Abs(c * H) + Abs(s * W));
DestBMP.Width := round(Abs(s * H) + Abs(c * W));
DCX := DestBMP.Width div 2;
DCY := DestBMP.Height div 2;
SetLength(pSource, H); FOR Y := 0 TO H-1 DO
pSource[Y] := SourceBMP.Scanline[Y];
//--- Linear interpolation. Slower, but looks much better... FOR Y := DestBMP.Height-1 DOWNTO 0 DO BEGIN
pDest := DestBMP.ScanLine[Y];
iX := 0; FOR X := 0 TO DestBMP.Width-1 DO BEGIN
dRX := SCX + ( c * (X-DCX) - s * (Y-DCY));
dRY := SCY + ( s * (X-DCX) + c * (Y-DCY)); IF (dRX >= 1) and (dRY >= 1) and (dRX < W-1) and (dRY < H-1) thenbegin
fX := frac(dRX);
fY := frac(dRY);
RX := trunc(dRX)*3; // "*3" because of 24 bit images
RY := trunc(dRY);
d := 1-fY;
pDest^[iX] := trunc(c11*(d) + c21*fY);
Inc(iX);
pDest^[iX] := trunc(c12*(d) + c22*fY);
Inc(iX);
pDest^[iX] := trunc(c13*(d) + c23*fY);
Inc(iX); end elsebegin
RX := trunc(dRX);
RY := trunc(dRY); // No linear interpolation for pixels at the outer rim // Those pixels were copied like in the nearest neighbour algorithm. IF (RX >= 0) and (RY >= 0) and (RX < W) and (RY < H) thenbegin
move(pSource[RY]^[RX*3], pDest^[iX], 3); end elsebegin// Pixel completely outside of the original image
move(RGBBack, pDest^[iX], 3); end;
Inc(iX, 3); end; END; END;
SetLength(pSource, 0); END;
Eine Gegenüberstellung kann man sich mit dem Demo-Projekt im Anhang verschaffen.