So... ich beantworte dann mal selbst.
Vorweg: ich habe es bislang nicht hinbekommen, eine TBitmap mit 32bit und Alpha in eine TGPBitmap oder ein TGPImage zu kopieren, ohne dass der Alphakanal verschwindet. Die TGPBitmap wird immer als 32bppRGB, nicht als 32bppARGB erzeugt.
Mein Umweg läuft darüber, erst die TBitmap in ein TPNGImage zu wandeln, dieses in einen Stream zu schreiben und aus dem Stream ein TGPImage zu erzeugen:
Code:
procedure RotateBitmapGDI(Bmp: TBitmap; Degs: Integer; AdjustSize: Boolean;
BkColor: TColor = clNone);
var
Tmp: TGPImage;
Matrix: TGPMatrix;
C: Single;
S: Single;
NewSize: TSize;
Graphs: TGPGraphics;
fstream: TStream;
tmpi: TGPIMage;
png: TPNGImage;
begin
//TBitmap (pf32, Alphatransparenz) nach PNG
png:=TPngImage.Create;
png:=Png4TransparentBitmap(bmp);
//PNG in Stream und nach TGPImage
fstream:=TMemoryStream.Create;
try
png.SaveToStream(fstream);
fstream.Position:=0;
tmp:=TGPImage.Create(TStreamAdapter.Create(fstream));
finally
fstream.Free;
png.Free;
end;
//die TBitmap löschen:
bmp.SetSize(0,0);
bmp.SetSize(120,120);
Matrix := TGPMatrix.Create;
try
Matrix.RotateAt(Degs, MakePoint(0.5 * Bmp.Width, 0.5 * Bmp.Height)); //Rotation
if AdjustSize then
begin
C := Cos(DegToRad(Degs));
S := Sin(DegToRad(Degs));
NewSize.cx := Round(Bmp.Width * Abs(C) + Bmp.Height * Abs(S));
NewSize.cy := Round(Bmp.Width * Abs(S) + Bmp.Height * Abs(C));
Bmp.Width := NewSize.cx;
Bmp.Height := NewSize.cy;
end;
Graphs := TGPGraphics.Create(Bmp.Canvas.Handle); //den Canvas der ursprünglichen TBitmap auswählen
try
//Graphs.Clear(ColorRefToARGB(ColorToRGB(BkColor)));
Graphs.SetTransform(Matrix);
Graphs.DrawImage(tmp, (Cardinal(Bmp.Width) - Tmp.GetWidth) div 2, (Cardinal(Bmp.Height) - Tmp.GetHeight) div 2); //zurückschreiben
finally
Graphs.Free;
end;
finally
Matrix.Free;
Tmp.Free;
end;
end;
Das ganze benutzt noch diese Hilfsprozedur:
Code:
function PNG4TransparentBitMap(bmp:TBitmap):TPNGImage;
//201011 Thomas Wassermann
var
x, y:Integer;
vBmpRGBA: ^TRGBAArray;
vPngRGB: ^TRGB;
begin
Result := TPNGImage.CreateBlank(COLOR_RGBALPHA, 8, bmp.Width , bmp.Height);
Result.CreateAlpha;
Result.Canvas.CopyMode:= cmSrcCopy;
Result.Canvas.Draw(0,0,bmp);
for y := 0 to pred(bmp.Height) do begin
vBmpRGBA := bmp.ScanLine[y];
vPngRGB:= Result.Scanline[y];
for x := 0 to pred(bmp.width) do begin
Result.AlphaScanline[y][x] := vBmpRGBA[x].A;
if bmp.AlphaFormat in [afDefined,afPremultiplied] then begin
if vBmpRGBA[x].A <> 0 then begin
vPngRGB^.b:= round(vBmpRGBA[x].b/vBmpRGBA[x].A*255);
vPngRGB^.r:= round(vBmpRGBA[x].r/vBmpRGBA[x].A*255);
vPngRGB^.g:= round(vBmpRGBA[x].g/vBmpRGBA[x].A*255);
end else begin
vPngRGB^.b:= round(vBmpRGBA[x].b*255);
vPngRGB^.r:= round(vBmpRGBA[x].r*255);
vPngRGB^.g:= round(vBmpRGBA[x].g*255);
end;
end;
inc(vPngRGB);
end;
end;
end;
Das ist natürlich irgendwie von-hinten-durch-die-Brust-ins-Auge und nicht gerade schnell (was in meinem Fall nichts ausmacht), aber alle anderen Varianten, die ich direkt mit der Ursprungsbitmap ausprobiert habe - ohne den Umweg über PNG - funktionierten nicht.
Ich kann aber nicht ganz glauben, dass das "normale"
GDI (mittlerweile) ohne Probleme mit 32Bit-TBitmaps mit Alphatransparenz arbeitet, aber die TGPBitmaps von
GDI+ die Alphainformation nicht aus einer TBitmap (direkt) übernehmen können.
Kennt jemand eine schnellere Lösung?
VG
Sven