![]() |
Grenzen von PlgBlt
Liste der Anhänge anzeigen (Anzahl: 1)
Ich weiß nicht, ob die Frage nicht besser bei Multimedia/Grafik stehen sollte. Da es aber eine Windows-Funktion betrifft, stelle ich sie hier. Notfalls kann sie durch den Moderator verschoben werden:
Ich bin - nach wie vor - auf der Suche nach einer schnellen und einfachen Methode, um ein 1-Bit-Bitmap (schwarz/weiß) zu drehen. Dabei kommt man an PlgBlt nicht vorbei und wie das geht, weiß ich im Grunde. Ich habe aber das ![]() Ich habe mal meinen Quelltext angehängt. Das kleine Bitmap lässt sich drehen, das große nicht. Bei letzterem werden nur noch Höhe und Breite miteinander vertauscht. Ich habe schon alle möglichen Hinweise im Netz gelesen, bin aber nicht wirklich auf etwaige Einschränkungen gestoßen. Was macht ich verkehrt? Gruß und Dank, Alex |
Re: Grenzen von PlgBlt
Zitat:
EDIT: aber sehe gerade! Zitat:
|
Re: Grenzen von PlgBlt
Danke für die Antwort!
Zitat:
![]() ![]() Kann ich da jede beliebige nehmen? Zu FlipRotatePicture selbst habe ich leider noch nichts gefunden. Ich habe mir Deine(?) Demos mit der Uhr etc. angesehen. Das sieht sehr vielversprechend aus, auch wenn es nur kleine Bilder sind. Ich möchte etwas ab 3.000 x 4.000 aufwärts drehen... |
Re: Grenzen von PlgBlt
Zitat:
|
Re: Grenzen von PlgBlt
Habe mal mein Archiv angehängt.
Hoffe das ist erlaubt. Habe unter .. Using Images, Bitmaps, and Metafiles/Rotating, Reflecting, and Skewing Images Das Sample ein bißchen modifiziert und mit deinen großen Bitmap geladen. Es funktioniert. Das Archiv ist so gross weil dein Bitmap enthalten ist. hmm 1,8MB gruss Emil |
Re: Grenzen von PlgBlt
Liste der Anhänge anzeigen (Anzahl: 1)
Zitat:
Mein erstes Archiv ist auch nur 68 KB groß und da sind 2 große Dateien drin! :lol: Es liegt eher daran, dass nun die ganze GDI+ Implementierung für Delphi auf dem Server bei DelphiPraxis.net rumlungert. Du kannst ja mit EDIT das Archiv aus Deinem Beitrag wieder rausnehmen. Den Link zu GDI+ findet man in meinem ersten Post und Dein Beispiel habe ich jetzt als kleines Archiv mit meiner 1,8 MB Datei beigefügt. Es ist jetzt etwas größer. Denn ich habe die exe mit dringelassen, falls jemand experimentieren aber nicht GDI+ runterladen möchte. Werde mal sehen, wie weit ich damit komme... Gruß und Dank, Alex |
Re: Grenzen von PlgBlt
Beachte..
Du mußt ja nicht alles einbinden. Lade die DLL dynamisch und kopiere nur den teil in dein Projekt den du verwendest. Für eine Funktion über 1 MB an Daten hinzuzufügen ist etwas viel denk ich mal. In meinen Uhr Projekt ist ne *.pas wo du die initialisierung von GDI+ von verwenden kannst Du brauchst GdipImageRotateFlip, GdipCreateBitmapFromHBITMAP und die type natürlich das ist alles. gruss Emil |
Re: Grenzen von PlgBlt
Zitat:
Ich bin grad am Grübeln: Wie bekomme ich mein TBitmap in das TGPImage gezeichnet? :gruebel: Für die Demo ist das Vorgehen ja OK. Aber ich brauche es (später) zum Bearbeiten von Bildern, die frisch aus dem Scanner kommen. Ich verfüge nicht über das Wissen bzw. die Kapazitäten mein geliebtes TDelphiTwain umzuschreiben. Und von dort bekomme ich "nur" TBitmaps geliefert. Die gilt es zu bearbeiten. Ein Assign() habe ich leider nicht gefunden. Gruß, Alex |
Re: Grenzen von PlgBlt
GdipCreateBitmapFromHBITMAP oder umgekehrt GdipCreateHBITMAPFromBitmap
Kann dir nur anraten mein Beispiel anzuschauen da ist alles drin ;) gruss Emil |
Re: Grenzen von PlgBlt
Zitat:
![]() ![]() Ich vermute anhand der mir ausgegebenen Zeiten, dass ich erfolreich dem HBITMAP ein TBitmap zugewiesen und vermutlich auch gedreht habe. Den Code habe ich mir unter anderem ![]()
Delphi-Quellcode:
Leider kann ich mit dem Ergebnis nichts anfangen. Ich weiß nicht, wie ich es wieder auf das TImage bzw. TImage.Bitmap bekomme oder abspeichern kann. :wall:
Type
TForm1 = Class(TForm) Image1 : TImage; End; ... Procedure TForm1.Image1Click(Sender: TObject); Var FlipBild : TGPBitmap; Zeit : Int64; Begin Zeit:=GetTickCount; FlipBild:=TGPBitmap.Create(Image1.Picture.Bitmap.Canvas.Handle,Image1.Picture.Bitmap.Palette); Try FlipBild.RotateFlip(Rotate90FlipNone); Finally FlipBild.Free; End; Zeit:=GetTickCount-Zeit; Caption:=Application.Title+' ['+FormatFloat('#,##0',Zeit)+' ms]'; End; ... End. Das Beispiel mit der Uhr ist zwar genial; für mich aber zu kompliziert und mit 5 Units zu unübersichtlich. Ich habe genau 1 Mal die Funktion GdipCreateHBITMAPFromBitmap gefunden, konnte damit aber nichts anfangen. Die Syntax zeigt mir Delphi ja automatisch an. Aber ohne das Wissen über die Variablen und was die bewirken/speichern können, komme ich nicht weiter. Dazu müsste ich dann wieder was lesen und ... Gute Nacht, Alex |
Re: Grenzen von PlgBlt
Hab mal schnell was geschrieben:
Delphi-Quellcode:
Edit: Hoffe es ist einfach genug. :wink:
procedure Rotiere(ABitmap: TBitmap; ADirection: Integer);
{---} const PIXELCOUNT = 8; {---} function Rol(const AByte, APositions: Byte): Byte register; asm mov cl, dl rol al, cl end; {---} function Ror(const AByte, APositions: Byte): Byte register; asm mov cl, dl ror al, cl end; {---} function CalcByteCount(AWidth: Integer): Integer; begin Result := AWidth div PIXELCOUNT; if (AWidth mod PIXELCOUNT) > 0 then Inc(Result); end; {---} var y, x1, x2, yMax, i, xCount, yCount: Integer; p1, p2, buffer: ^Byte; v, m: Byte; begin {im Uhrzeigersinn drehen} if (ADirection = 90) or (ADirection = 180) or (ADirection = 270) then begin ABitmap.Pixelformat := pf1Bit; xCount := CalcByteCount(ABitmap.Width); yCount := CalcByteCount(ABitmap.Height); GetMem(buffer, xCount * yCount * PIXELCOUNT); try FillChar(buffer^, xCount * yCount * PIXELCOUNT, #0); yMax := ABitmap.Height - 1; if ADirection = 90 then begin m := 1 shl (PIXELCOUNT - 1); for y := yMax downto 0 do begin p1 := ABitmap.Scanline[y]; p2 := buffer; Inc(p2, (yMax - y) div PIXELCOUNT); for x1 := 0 to xCount - 1 do begin v := p1^; for x2 := 0 to PIXELCOUNT - 1 do begin v := Rol(v, 1); if Odd(v) then p2^ := p2^ or m; Inc(p2, yCount); end; Inc(p1, 1); end; m := Ror(m, 1); end; ABitmap.SetSize(ABitmap.Height, ABitmap.Width); p2 := buffer; end else if ADirection = 270 then begin m := 1 shl (PIXELCOUNT - 1); for y := 0 to yMax do begin p1 := ABitmap.Scanline[y]; Inc(P1, xCount - 1); p2 := buffer; Inc(p2, (y div PIXELCOUNT)); for x1 := 0 to xCount - 1 do begin v := p1^; for x2 := 0 to PIXELCOUNT - 1 do begin if Odd(v) then p2^ := p2^ or m; v := Ror(v, 1); Inc(p2, yCount); end; Dec(p1, 1); end; m := Ror(m, 1); end; ABitmap.SetSize(ABitmap.Height, ABitmap.Width); p2 := buffer; {Leerzeilen überspringen} Inc(p2, yCount * ((xCount * PixelCount) - ABitmap.Height)); end else if ADirection = 180 then begin p2 := buffer; i := (ABitmap.Width mod PIXELCOUNT); for y := yMax downto 0 do begin p1 := ABitmap.Scanline[y]; Inc(P1, xCount - 1); if i = 0 then v := 0 else begin v := p1^; Dec(p1); v := Rol(v, i); end; for x1 := 0 to xCount - 1 do begin m := 0; for x2 := 0 to i - 1 do begin m := Rol(m, 1); if Odd(v) then m := m or 1; v := Ror(v, 1); end; if (i > 0) and (x1 = (xCount - 1)) then v := 0 else begin v := p1^; Dec(P1); end; for x2 := i to PIXELCOUNT - 1 do begin m := Rol(m, 1); if Odd(v) then m := m or 1; v := Ror(v, 1); end; p2^ := m; Inc(p2); end; end; p2 := buffer; end else Exit; {Bitmap aus dem Buffer füllen} xCount := CalcByteCount(ABitmap.Width); for y := 0 to ABitmap.Height - 1 do begin p1 := ABitmap.Scanline[y]; Move(p2^, p1^, xCount); Inc(p2, xCount); end; finally FreeMem(Buffer); end; end; end; |
Re: Grenzen von PlgBlt
Zitat:
Ich habe nur gedacht, dass die Funktionen von GDI+ übersichtlich sind. Das sind sie wohl auch. Kürzer und einfacher als FlipBild.RotateFlip(Rotate90FlipNone); ist ja kaum vorstellbar. Aber wenn ich erhebliche Klimmzüge starten muss, um mein TBitmap in alle möglichen anderen Typen und wieder zurück zu verwandeln, dann ist es für mich nicht nutzbar. Ich wäre gern bei GDI+ geblieben bzw. erstmal dorthin gekommen, weil ich das Bild vor/nach dem Drehen noch strecken bzw. stauchen muss. Und dafür scheint es ja auch Einiges bereit zu halten ... Vielen herzlichen Dank sagt Alex |
Re: Grenzen von PlgBlt
Zitat:
Für mich war es etwas einfacher da es unter VB viele anleitungen und samples gibt von denen man lernen kann. In Delphi gibt es da fast so gut wie nichts. Was du am ende benutzt mußt du selbst wissen. Es soll ja funktionieren. ;) gruss Emil |
Re: Grenzen von PlgBlt
Liste der Anhänge anzeigen (Anzahl: 1)
Zitat:
Aber ich bin doch tatsächlich ein gutes Stück weiter. Mein Vorteil ist, dass ich die Bilder "nur" verarbeiten und dann speichern muss. Das Darstellen usw. ist für mich unwichtig. Und so ist es mir zwischenzeitlich gelungen, mein TBimap einem TGPBitmap zuzuweisen und nach anfägnlichen Schwierigkeiten auch zu speichern. Ich habe den Code als Archiv angehängt für Interessierte. Dazu habe ich eine Frage: 1. Mit der Funktion
Delphi-Quellcode:
sage ich - nach meinem Verständnis -, dass GDIPBitmap den Speicherbereich von Image1.Picture.Bitmap benutzen soll. Da aber Image1 den Speicher nicht freigibt, müssten die Operationen, die ich mache auch Image1 betreffen und evtl. sogar angezeigt werden. Wo liegt mein Missverständnis?
GDIPBitmap:=TGPBitmap.Create(Image1.Picture.Bitmap.Handle,
Image1.Picture.Bitmap.Palette); Gruß und Danke für die Vorschlage, Hilfen und Ermunterungen Alex |
Re: Grenzen von PlgBlt
Zitat:
Habs auch mit deiner großen Bitmap probiert. Was genau klappt den nicht, bzw. wie sieht das Ergebnis aus? |
AW: Re: Grenzen von PlgBlt
Hallo,
mit der Zeit werde auch ich schlauer und habe somit gelernt, wie man DLL-Funktionen einbinden kann :lol:. Ich habe jetzt in den Implementations-Teil meiner "Dreh-Unit" folgendes geschrieben:
Delphi-Quellcode:
Die Deklaration von RotateFlipType habe ich jetzt mal außen vor gelassen. Die Deklaration von GPStatus ist nicht auf meinem Mist gewachsen, sonder ich habe sie einfach aus der Unit GDIPAPI.pas von
Const
Status = (Ok, GenericError, InvalidParameter, OutOfMemory, ObjectBusy, InsufficientBuffer, NotImplemented, Win32Error, WrongState, Aborted, FileNotFound, ValueOverflow, AccessDenied, UnknownImageFormat, FontFamilyNotFound, FontStyleNotFound, NotTrueTypeFont, UnsupportedGdiplusVersion, GdiplusNotInitialized, PropertyNotFound, PropertyNotSupported); TStatus = Status; GpStatus = TStatus; Function GdipImageRotateFlip(Image: Pointer; rfType: ROTATEFLIPTYPE): GPSTATUS; Stdcall; External 'gdiplus.dll'; ![]() Und so sollte das dann von mir aufgerufen werden:
Delphi-Quellcode:
TImage.Picture.Bitmap.Handle ist doch vom Typ HBITMAP. Ist das eine anderes HBITMAP als es GDI+ benutzt?
Procedure TMainForm.BtnRotateClick(Sender: TObject);
Var Stat : GPStatus; tmp : HBitmap; Begin tmp:=Image1.Picture.Bitmap.Handle; Stat:=GdipImageRotateFlip(@tmp, Rotate90FlipNone); ShowMessage(StatusText[Stat]); End; Denn ich bekomme immer die Statusmeldung "ObjectBusy" zurück. Erwartet hatte ich eigentlich "GdiplusNotInitialized", weil ich genau das nicht getan habe; Initialisieren. Könnte mir bei der Gelegenheit bitte mal jemand ein Beispiel posten, wie ich mit den Funktionen "GdipCreateBitmapFromHBITMAP" bzw. "GdipCreateHBITMAPFromBitmap" ein TBitmap aus Delphi in ein GDI+-konformes HBITMAP umwandeln kann und umgekehrt? Mehr als das und "GdipImageRotateFlip" brauche ich vermutlich wirklich nicht, so dass mein Code übersichtlich und mein Programm schön klein bliebe! Bitte, bitte, Alex |
AW: Re: Grenzen von PlgBlt
Der "falsche" Fehlercode kommt wohl daher, dass ich GDI+ nicht initialisiert hatte. Jetzt klappt es mit dem Erzeugen durch
Delphi-Quellcode:
. Der Status passt und der Pointer auf das Image ist nicht mehr
GdipCreateBitmapFromHBITMAP()
Delphi-Quellcode:
.
nil
Allerdings erhalt ich nun beim Aufruf von
Delphi-Quellcode:
als Status-Rückmeldung
GdipImageRotateFlip
Delphi-Quellcode:
wobei folgendes definiert ist:
InvalidParameter
Delphi-Quellcode:
Auch das stammt nicht von mir, sondern ist ein Ausschnitt aus der von mir bereits zitierten Unit.
Type
RotateFlipType= (RotateNoneFlipNone = 0, Rotate90FlipNone = 1, Rotate180FlipNone = 2, Rotate270FlipNone = 3, RotateNoneFlipX = 4, Rotate90FlipX = 5, Rotate180FlipX = 6, Rotate270FlipX = 7, RotateNoneFlipY = Rotate180FlipX, Rotate90FlipY = Rotate270FlipX, Rotate180FlipY = RotateNoneFlipX, Rotate270FlipY = Rotate90FlipX, RotateNoneFlipXY = Rotate180FlipNone, Rotate90FlipXY = Rotate270FlipNone, Rotate180FlipXY = RotateNoneFlipNone, Rotate270FlipXY = Rotate90FlipNone); Status = (Ok, GenericError, InvalidParameter, OutOfMemory, ObjectBusy, InsufficientBuffer, NotImplemented, Win32Error, WrongState, Aborted, FileNotFound, ValueOverflow, AccessDenied, UnknownImageFormat, FontFamilyNotFound, FontStyleNotFound, NotTrueTypeFont, UnsupportedGdiplusVersion, GdiplusNotInitialized, PropertyNotFound, PropertyNotSupported); TStatus = Status; GpStatus = TStatus; Was mache ich denn nun wieder falsch? Mein Ziel ist es nachwievor, einfach nur ein TBitmap herzunehmen, in ein GDI+Bild umzuwandeln, dieses zu drehen und dann wieder in ein TBitmap zurückzuwandeln. |
AW: Re: Grenzen von PlgBlt
Ich antworte nun mal selbst:
ich habe es mit den Funktionen hinbekommen. Offenbar gelten die Grenzen von
Delphi-Quellcode:
bedauerlicher Weise auch für
PlgBlt()
Delphi-Quellcode:
. Die Ursache für die Speicherzugriffsverletzungen und sonstigen Fehlermeldungen war schlicht die, dass mein Test-Bild zu groß ist. Benutze ich ein kleineres Bild, dann klappt das ganze prima.
GdipImageRotateFlip()
Es gibt bloß ein Speicherleck, dass ich mit FastMM nicht eingrenzen kann. Bei jedem Drehen, braucht das Programm mehr Speicher und FastMM zeigt beim Beenden rein garnichts an. Ich habe sogar schon Speicherlecks provoziert, die gezeigt werden. Aber der andere Verbrauch ist unergründlich. Da ich also die API von Windows wohl vergessen kann, muss ich mir jetzt überlegen, wie ich ![]() Gruß, Alex |
AW: Grenzen von PlgBlt
Ich nutze GID+ sehr ausgiebig, allerdings mit Streams und Painroutinen, falls Du schnelle und einfache Canvasroutinen brauchen solltest, kann du ja hie mal bohren und erweitern:
Delphi-Quellcode:
unit ExCanvasTools;
// 20100915 by Thomas Wassermann interface uses Windows, SysUtils, Classes, Graphics; Function Grad2Rad(w:Double):Double; Procedure PaintGraphic(ACanvas:TCanvas;x,y:Integer;AGraphic:TGraphic;Faktor,Winkel:Double;PosIsCenter:Boolean=false); Procedure PaintText(ACanvas:TCanvas;Const s:String;x,y:Integer;Faktor,Winkel:Double;PosIsCenter:Boolean=false); Procedure ResetCanvas(ACanvas:TCanvas); procedure SetCanvasZoomAndRotation(ACanvas: TCanvas;Zoom:Double;Angle:Double;CenterpointX,CenterpointY:Double); implementation Function Grad2Rad(w:Double):Double; begin Result := w / 360 * PI *2; end; Procedure PaintText(ACanvas:TCanvas;Const s:String;x,y:Integer;Faktor,Winkel:Double;PosIsCenter:Boolean=false); var px,py:Integer; begin SetCanvasZoomAndRotation(ACanvas , Faktor, Winkel, x,y); if PosIsCenter then begin px := Round( ACanvas.TextWidth(s) / 2 ); py := Round( ACanvas.TextHeight(s) / 2 ); end else begin px := 0; py := 0; end; ACanvas.TextOut(-px ,-py ,s); ResetCanvas(ACanvas); end; Procedure PaintGraphic(ACanvas:TCanvas;x,y:Integer;AGraphic:TGraphic;Faktor,Winkel:Double;PosIsCenter:Boolean=false); var px,py:Integer; begin if PosIsCenter then begin px := Round( AGraphic.Width / 2 ); py := Round( AGraphic.Height / 2 ); end else begin px := 0; py := 0; end; SetCanvasZoomAndRotation(ACanvas , Faktor, Winkel, x , y ); ACanvas.Draw(-px ,-py ,AGraphic); ResetCanvas(ACanvas); end; Procedure ResetCanvas(ACanvas:TCanvas); begin SetCanvasZoomAndRotation(ACanvas , 1, 0, 0,0); end; Procedure SetCanvasZoomAndRotation(ACanvas:TCanvas;Zoom:Double;Angle:Double;CenterpointX,CenterpointY:Double); var form : tagXFORM; Winkel:Double; begin Winkel := Grad2Rad(Angle); SetGraphicsMode(ACanvas.Handle, GM_ADVANCED); SetMapMode(ACanvas.Handle,MM_ANISOTROPIC); form.eM11 := Zoom * cos( Winkel); form.eM12 := Zoom *Sin( Winkel) ; form.eM21 := Zoom * (-sin( Winkel)); form.eM22 := Zoom * cos( Winkel) ; form.eDx := CenterpointX; form.eDy := CenterpointY; SetWorldTransform(ACanvas.Handle,form); end; end. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 01:31 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