![]() |
Transparentes PNG in TImage drehen...Wie?
Liste der Anhänge anzeigen (Anzahl: 1)
Hallo Wissende,
ich habe mir aus diversen Threads mal genau das "gebaut", was ich eigentlich bräuchte. Leider funzt das Ganze so gar nicht. Es liegt ein TImage auf einem Form, welches schon ein tranparentes PNG beinhaltet. Zu sehen ist ein Pfeil. Darunter befindet sich eine Trackbar. Wenn ich an dieser nun schiebe, soll sich die Graphik ensprechend drehen. Ich brauche es unbedingt mit png. Was mache ich da falsch? Das Projekt hängt im Anhang und der Code, so viel ist es ja nicht, ist hier:
Delphi-Quellcode:
unit Unit1;
interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, ComCtrls, pngimage, ExtCtrls,Math, JvGradient, StdCtrls ; type TForm1 = class(TForm) TrackBar1: TTrackBar; Image2: TImage; lbl_position: TLabel; Image1: TImage; procedure TrackBar1Change(Sender: TObject); procedure FormCreate(Sender: TObject); private { Private-Deklarationen } public { Public-Deklarationen } end; var Form1: TForm1; implementation {$R *.dfm} procedure DrawRotatedGraphic (aCanvas: TCanvas; aGraphic: TGraphic; aAngle: Double; aOffsetX, aOffsetY: Integer); var svMode: Integer; Mat, svMat: tagXFORM; si, co: Extended; begin // aktuellen Zustand retten svMode := SetGraphicsMode(aCanvas.Handle, GM_ADVANCED); if (svMode = GM_ADVANCED) then GetWorldTransform(aCanvas.Handle, svMat); // Verschiebung in den Usprung FillChar (Mat, SizeOf(Mat), 0); Mat.em11 := 1.0; Mat.em22 := 1.0; Mat.eDx := -(aOffsetX + aGraphic.Width / 2); Mat.eDy := -(aOffsetY + aGraphic.Height / 2); SetWorldTransform(aCanvas.Handle, Mat); // Verdrehung SinCos (aAngle * Pi / 180, si, co); FillChar (Mat, SizeOf(Mat), 0); Mat.em11 := co; Mat.em12 := si; Mat.em21 := -si; Mat.em22 := co; ModifyWorldTransform(aCanvas.Handle, Mat, MWT_RIGHTMULTIPLY); // Zurückschieben FillChar (Mat, SizeOf(Mat), 0); Mat.em11 := 1.0; Mat.em22 := 1.0; Mat.eDx := (aOffsetX + aGraphic.Width / 2); Mat.eDy := (aOffsetY + aGraphic.Height / 2); ModifyWorldTransform(aCanvas.Handle, Mat, MWT_RIGHTMULTIPLY); // Bitmap zeichnen aCanvas.Draw(aOffsetX, aOffsetY, aGraphic); // alten Zustand wiederherstellen if (svMode = GM_ADVANCED) then SetWorldTransform(aCanvas.Handle, svMat) else SetGraphicsMode(aCanvas.Handle, svMode); end; procedure TForm1.TrackBar1Change(Sender: TObject); begin lbl_position.Caption:=inttostr(TrackBar1.Position); DrawRotatedGraphic(Image2.Canvas,Image2.Picture.Graphic,TrackBar1.Position,0,0); end; procedure TForm1.FormCreate(Sender: TObject); begin lbl_position.Caption:=inttostr(TrackBar1.Position); end; end. |
Re: Transparentes PNG in TImage drehen...Wie?
hmm...
Cool, wußte garnicht das es sowas gibt... Kann keinen Fehler in Deinem Source finden... Bist Du sicher, dass das auch mit einem Screen_Canvas geht? Frank |
Re: Transparentes PNG in TImage drehen...Wie?
Ja ja es geht schon, aber eben nur, wenn ich mir die Source aus nem anderen TImage hole und dann auch nicht transparent. Aber ich bin mir fast sicher, dass es irgendwie geht...
|
Re: Transparentes PNG in TImage drehen...Wie?
Also bei mir funktioniert es nicht...
Außerdem kann ein BMP ja auch Transparent sein... Frank |
Re: Transparentes PNG in TImage drehen...Wie?
Liste der Anhänge anzeigen (Anzahl: 1)
So, nun habe ich das Projekt mal etwas modifiziert, damit man sehen, kann wie es eigentlich funktionieren sollte. Das linke Image im Projekt wird als Source genommen, gedreht und dem rechten Image zugewiesen.
So weit so gut. Problem dabei ist, dass die Transparenz des png´s verloren geht. Weiss jemand, wie ich das händeln muss, damit das nicht passiert? |
Re: Transparentes PNG in TImage drehen...Wie?
Dann musst du eben von deinem PNG die alpha-maske rausholen, die RGB-Werte und die Alpha-Maske rotieren, und dann auf ein neues png zuweisen. (kannst dir die sache erleichtern, indem du die alpha-maske in ein graustufen-bitmap schriebst, das dann rotierst und dir dann die werte ins png zurückschreibst)
|
Re: Transparentes PNG in TImage drehen...Wie?
Soweit ich das sehe, hast Du ein BMP genommen und kein PNG? Oder?
Frank |
Re: Transparentes PNG in TImage drehen...Wie?
ich werde es mal checken und das Projekt notfalls angepasst hochladen. wird aber nicht vor mitternacht. :-)
@lukas - danke für den tipp, aber sowas habe ich noch nicht gemacht...hast du vielleicht ein beispiel? |
Re: Transparentes PNG in TImage drehen...Wie?
Zitat:
Im TGraphic sind die Alpha Informationen nicht verfügbar. Dazu musst Du das TPNGObject verwenden. Gustavo Daud (der Ersteller der PngDelphi) hat das in einem Beispiel so gemacht:
Delphi-Quellcode:
Damit kannst Du das PNG in dem TImage inkl. der Transparenz bzw Alpha Infos drehen.
{Smooth rotate a png object}
procedure SmoothRotate(var aPng: TPNGObject; Angle: Extended); Hier ist der Link: ![]() Ich hoffe, dass bringt Dich weiter... |
Re: Transparentes PNG in TImage drehen...Wie?
Zitat:
![]() Bzw. leicht abgewandelt:
Delphi-Quellcode:
procedure TForm1.DrawOverForm(filename: String; X, Y: Integer);
var PNG: TPNGObject; begin PNG := TPNGObject.Create; try PNG.LoadFromFile(filename); PNG.Draw(Canvas, Rect(X, Y, X + PNG.Width, Y + PNG.Height)); finally PNG.Free; end; end; |
Re: Transparentes PNG in TImage drehen...Wie?
Zitat:
Sorry, wenn ich mich vielleicht etwas blöd anstelle, aber wie übergebe ich denn der Routine SmoothRotate das pnpObjekt aus dem TImage? Ansonsten bin ich mir sehr sicher, dass das genau das Richtige ist... Und um es vielleicht noch kurz erklären, warum ich PNG in einem TImage verwende. Ich erstelle Pläne auf einem Form. Auf diesen Plänen sind diverse TImages, die der User frei hinzufügen und bewegen kann (TImages mit geladenen PNG´s). Nun will/muss ich aber für bestimmte Bilder einfach anbieten, dass man die Bilder vor dem Hinzufügen über einen Dialog noch drehen kann. Wenn das funktioniert, will ich dann auch noch nachträglich, die einem Plan hinzugefügten Bilder drehen lassen... |
Re: Transparentes PNG in TImage drehen...Wie?
Zitat:
Ein TImage kann diese Informationen nicht speichern. Nach dem Laden ist der Alpha-Kanal weg. Oder??? bzw. Das Image in Deinem Beispiel kann eine PNG Datei nicht laden... Daher gehe ich davon aus, dass Du eine andere Komponente hast... Frank :coder: |
Re: Transparentes PNG in TImage drehen...Wie?
Zitat:
TImage kann über die Filter (z.B. pngdelphi) auch mit PNG Dateien umgehen. Da das TImage ja auch wissen muß wie es gezeichnet wird müssen die Infos ja irgendwo da drin sein :mrgreen: Also:
In der Delphi Onlinehilfe steht: Graphic (Eigenschaft von TPicture) Die Eigenschaft Graphic gibt die im TPicture-Objekt enthaltene Grafik an.
Delphi-Quellcode:
Beschreibung
property Graphic: TGraphic;
Mit Graphic legen Sie den Grafiktyp fest, die das TPicture-Objekt enthält. Ein TPicture-Objekt kann Grafiken des Typs Bitmap, Symbol, Metadatei oder benutzerdefinierte Grafikklassen enthalten. Folgender Code sollte Dein Problem lösen: (gibt aber Fehler, wenn Im TImage kein Bild geladen ist, das sollte mit Assigned() noch abgefangen werden.)
Delphi-Quellcode:
Viel Spaß
procedure TForm1.BitBtn1Click(Sender: TObject);
var x: TPNGObject; begin // Ist da überhaupt ein PNG drin? if Image1.Picture.Graphic is TPngObject then begin // TPngObject(Image1.Picture.Graphic) ist ein konstanter Ausdruck // und kann nicht als Var Parameter übergeben werden, deshalb // Der Umweg über x ;-) x := Image1.Picture.Graphic as TPngObject; SmoothRotate(x, 20); end; end; MaBuSE |
Re: Transparentes PNG in TImage drehen...Wie?
Danke für die Hinweise und die Codes. Das hat mir wirklich SEHR weitergeholfen. Ich bin nun an dem Punkt, wo ich sagen kann, dass es grundsätzlich funktioniert, ABER, der Bildinhalt wird jedes mal verkleinert. Irgednwo ist da noch ein kleiner Fehler drin.
Delphi-Quellcode:
Ich habe die Routine nur um das Repaint erweitert. Das Assingment prüfe ich noch...Die Position kommt derzeit von einer Scrollbar.
procedure Tobjects.ScrollBar1Change(Sender: TObject);
var x: TPNGObject; begin // Ist da überhaupt ein PNG drin? if img_obj_prev.Picture.Graphic is TPngObject then begin // TPngObject(Image1.Picture.Graphic) ist ein konstanter Ausdruck // und kann nicht als Var Parameter übergeben werden, deshalb // Der Umweg über x ;-) x := img_obj_prev.Picture.Graphic as TPngObject; SmoothRotate(x, ScrollBar1.Position); img_obj_prev.Repaint; end; end; |
Re: Transparentes PNG in TImage drehen...Wie?
Zitat:
Ich hoffe Du verstehst was ich meine. ;-) [edit] Beispiel: Bild mit 20 x 10 Pixel wird um 90° gedreht es hat dann 10 x 20 Pixel. Wenn die Höhe des TImage jetzt immer noch 10 Pixel hat, wird das Bild um Faktor 2 verkleinert. Es ist nur noch halb so groß. [/edit] |
Re: Transparentes PNG in TImage drehen...Wie?
Liste der Anhänge anzeigen (Anzahl: 1)
Ok, ich habe mal wieder das Beispielprojekt angepasst und es dreht sich nur, was sich drehen soll, ABER die Qualität ist leider inakzeptabel und auch die Geschwindigkeit der Berechnung wird von mal zu mal langsamer. Desweiteren habe ich ja im Projekt als Beispiel zum Drehen eine Scrollbar genommen, womit ich dem User anbieten will, dass er das Bild von 1° auf 360° drehen kann. Das stimmt leider auch nicht ganz, denn mir scheint, als würde der Drehwinkel jedes mal grösser werden.
Mach ich da nun wieder was falsch? :roll: |
Re: Transparentes PNG in TImage drehen...Wie?
Zitat:
Aber ich habe eine Vermutung. Das Rotate macht wohl ein Anialiasing. Zitat:
Mein Vorschlag. Leg vor dem Drehen eine "Kopie" des PNG Bildes an. Drehe dann ein temp. Bild der Kopie und weise es danach der TImage Komponente zu. Ich mach mal ein Beisp. ;-) |
Re: Transparentes PNG in TImage drehen...Wie?
guter vorschlag! darauf hätte ich eigentlich auch selbst kommen müssen. wie kann ich es noch händeln, dass der rechner nicht so lange zu rechnen braucht, wenn ein user auf der scrollbar einen der beiden buttons permanent gedrückt hält? mit einer boolschen variable IsRunning, und wenn die noch true ist, einfach die aktion NICHT ausführen. macht das sinn?
|
Re: Transparentes PNG in TImage drehen...Wie?
Vergesst alles ab Guten Morgen. Es funzt nun - Jippi. Ich habe es erstmal "polnisch" gelöst, indem ich einfach nur ein unsichtbares TImage auf das Formular gelegt habe und den Code nur dahingehend geändert habe.
Delphi-Quellcode:
Und was soll ich sagen? Es ist wirklich ganz ok! Ich glaube, dass ich damit nun was anfangen kann...Danke an alle, die mitgeholfen haben.
procedure TForm1.ScrollBar1Change(Sender: TObject);
var x,y: TPNGObject; begin // Ist da überhaupt ein PNG drin? if img_src.Picture.Graphic is TPngObject then begin // TPngObject(Image1.Picture.Graphic) ist ein konstanter Ausdruck // und kann nicht als Var Parameter übergeben werden, deshalb // Der Umweg über x ;-) img_dest.Picture.Graphic.Assign(img_src.Picture.Graphic); x := img_dest.Picture.Graphic as TPngObject; SmoothRotate(x, ScrollBar1.Position); img_dest.Repaint; end; end; |
Re: Transparentes PNG in TImage drehen...Wie?
Ok, eine kleine Frage habe ich dann trotzdem noch, weil mich das Grössenproblem des Images doch noch beschäftigt. Ich eröffne dazu auch gern einen neuen Thread, aber ich bin froh, dass ich hier schon Hilfe gefunden habe und indirekt hängt es ja mit den mir zur Verfügung gestellten Sourcen zusammen.
So wie ich das Drehen des Bildes verstehe, wird das Bild in den gegebenen Bildgrössen gedreht. Somit können die Bildinhalte auch mal kleiner und auch grösser werden. Mir wäre es aber lieber, wenn das Bild nur gedreht werden würde und die Ausmasse des Bildes sich ändern würden. Damit wäre das zu drehende Bildobjekt für den User immer in der gleichen Grösse. In Photoshop ist das auch möglich... Wie könnte ich dass mit der vorhandenen Routine umsetzen? Mir ist schon klar, was ich verlange, aber ich dachte mir, dass es vielleicht reichen könnte, wenn man die in der Routine implementierte Funktion zur Grössenberechnung abklemmt oder umschreibt....Leider sind meine mathematischen Kenntnisse diesbezüglich eher mager... :(
Delphi-Quellcode:
procedure SmoothRotate(var aPng: TPNGObject; Angle: Extended);
{Supporting functions} function TrimInt(i, Min, Max: Integer): Integer; begin if i>Max then Result:=Max else if i<Min then Result:=Min else Result:=i; end; function IntToByte(i:Integer):Byte; begin if i>255 then Result:=255 else if i<0 then Result:=0 else Result:=i; end; function Min(A, B: Double): Double; begin if A < B then Result := A else Result := B; end; function Max(A, B: Double): Double; begin if A > B then Result := A else Result := B; end; function Ceil(A: Double): Integer; begin Result := Integer(Trunc(A)); if Frac(A) > 0 then Inc(Result); end; {Calculates the png new size} function newsize: tsize; var fRadians: Extended; fCosine, fSine: Double; fPoint1x, fPoint1y, fPoint2x, fPoint2y, fPoint3x, fPoint3y: Double; fMinx, fMiny, fMaxx, fMaxy: Double; begin {Convert degrees to radians} fRadians := (2 * PI * Angle) / 360; fCosine := abs(cos(fRadians)); fSine := abs(sin(fRadians)); fPoint1x := (-apng.Height * fSine); fPoint1y := (apng.Height * fCosine); fPoint2x := (apng.Width * fCosine - apng.Height * fSine); fPoint2y := (apng.Height * fCosine + apng.Width * fSine); fPoint3x := (apng.Width * fCosine); fPoint3y := (apng.Width * fSine); fMinx := min(0,min(fPoint1x,min(fPoint2x,fPoint3x))); fMiny := min(0,min(fPoint1y,min(fPoint2y,fPoint3y))); fMaxx := max(fPoint1x,max(fPoint2x,fPoint3x)); fMaxy := max(fPoint1y,max(fPoint2y,fPoint3y)); Result.cx := ceil(fMaxx-fMinx); Result.cy := ceil(fMaxy-fMiny); end; type TFColor = record b,g,r:Byte end; var Top, Bottom, Left, Right, eww,nsw, fx,fy, wx,wy: Extended; cAngle, sAngle: Double; xDiff, yDiff, ifx,ify, px,py, ix,iy, x,y, cx, cy: Integer; nw,ne, sw,se: TFColor; anw,ane, asw,ase: Byte; P1,P2,P3:Pbytearray; A1,A2,A3: pbytearray; dst: TPNGObject; IsAlpha: Boolean; new_colortype: Integer; begin {Only allows RGB and RGBALPHA images} if not (apng.Header.ColorType in [COLOR_RGBALPHA, COLOR_RGB]) then raise Exception.Create('Only COLOR_RGBALPHA and COLOR_RGB formats' + ' are supported'); IsAlpha := apng.Header.ColorType in [COLOR_RGBALPHA]; if IsAlpha then new_colortype := COLOR_RGBALPHA else new_colortype := COLOR_RGB; {Creates a copy} dst := tpngobject.Create; with newsize do dst.createblank(new_colortype, 8, cx, cy); cx := dst.width div 2; cy := dst.height div 2; {Gather some variables} Angle:=angle; Angle:=-Angle*Pi/180; sAngle:=Sin(Angle); cAngle:=Cos(Angle); xDiff:=(Dst.Width-apng.Width)div 2; yDiff:=(Dst.Height-apng.Height)div 2; {Iterates over each line} for y:=0 to Dst.Height-1 do begin P3:=Dst.scanline[y]; if IsAlpha then A3 := Dst.AlphaScanline[y]; py:=2*(y-cy)+1; {Iterates over each column} for x:=0 to Dst.Width-1 do begin px:=2*(x-cx)+1; fx:=(((px*cAngle-py*sAngle)-1)/ 2+cx)-xDiff; fy:=(((px*sAngle+py*cAngle)-1)/ 2+cy)-yDiff; ifx:=Round(fx); ify:=Round(fy); {Only continues if it does not exceed image boundaries} if(ifx>-1)and(ifx<apng.Width)and(ify>-1)and(ify<apng.Height)then begin {Obtains data to paint the new pixel} eww:=fx-ifx; nsw:=fy-ify; iy:=TrimInt(ify+1,0,apng.Height-1); ix:=TrimInt(ifx+1,0,apng.Width-1); P1:=apng.scanline[ify]; P2:=apng.scanline[iy]; if IsAlpha then A1 := apng.alphascanline[ify]; if IsAlpha then A2 := apng.alphascanline[iy]; nw.r:=P1[ifx*3]; nw.g:=P1[ifx*3+1]; nw.b:=P1[ifx*3+2]; if IsAlpha then anw:=A1[ifx]; ne.r:=P1[ix*3]; ne.g:=P1[ix*3+1]; ne.b:=P1[ix*3+2]; if IsAlpha then ane:=A1[ix]; sw.r:=P2[ifx*3]; sw.g:=P2[ifx*3+1]; sw.b:=P2[ifx*3+2]; if IsAlpha then asw:=A2[ifx]; se.r:=P2[ix*3]; se.g:=P2[ix*3+1]; se.b:=P2[ix*3+2]; if IsAlpha then ase:=A2[ix]; {Defines the new pixel} Top:=nw.b+eww*(ne.b-nw.b); Bottom:=sw.b+eww*(se.b-sw.b); P3[x*3+2]:=IntToByte(Round(Top+nsw*(Bottom-Top))); Top:=nw.g+eww*(ne.g-nw.g); Bottom:=sw.g+eww*(se.g-sw.g); P3[x*3+1]:=IntToByte(Round(Top+nsw*(Bottom-Top))); Top:=nw.r+eww*(ne.r-nw.r); Bottom:=sw.r+eww*(se.r-sw.r); P3[x*3]:=IntToByte(Round(Top+nsw*(Bottom-Top))); {Only for alpha} if IsAlpha then begin Top:=anw+eww*(ane-anw); Bottom:=asw+eww*(ase-asw); A3[x]:=IntToByte(Round(Top+nsw*(Bottom-Top))); end; end; end; end; apng.assign(dst); dst.free; end; |
Re: Transparentes PNG in TImage drehen...Wie?
Sorry, dass ich das Thema nach so langer Zeit wieder ausgrabe. Leider gibt es die Sourceforge-Seite zum PNGObject nicht mehr und ich stehe ebenfalls vor dem Problem ein PNGObject drehen zu müssen und den Alphakanal zu erhalten. Die zuletzt gepostete Funktion funktioniert leider überhaupt nicht (kompiliert nichteinmal, und wenn ich die Fehler behebe produziert sie Laufzeitfehler). Vlt hat ja jemand eine Lösung für das Problem?!
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 09:54 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz