Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Win32/Win64 API (native code) (https://www.delphipraxis.net/17-win32-win64-api-native-code/)
-   -   Delphi Grenzen von PlgBlt (https://www.delphipraxis.net/133592-grenzen-von-plgblt.html)

Schwedenbitter 5. Mai 2009 13:06


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 Problem, dass die Funktion ab einer bestimmten Größe des Bitmaps nicht mehr das tut, was sie soll; nämlich garnichts. Ich möchte aber gern bei der Funktion bleiben, weil Sie einfach zu handhaben ist, ich keine Komponenten von Hand einbinden muss (habe TurboDelphi 2006), ich nicht auf fremden Quelltext angewiesen bin und die "Farbinfo" des Bitmaps unangetastet bliebt.

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

EWeiss 5. Mai 2009 13:45

Re: Grenzen von PlgBlt
 
Zitat:

Dabei kommt man an PlgBlt nicht vorbei
Klar geht auch mit GDI+ Stichwort: FlipRotatePicture

EDIT:
aber sehe gerade!
Zitat:

Ich möchte aber gern bei der Funktion bleiben
gruss Emil

Schwedenbitter 5. Mai 2009 15:23

Re: Grenzen von PlgBlt
 
Danke für die Antwort!

Zitat:

Zitat von EWeiss
Klar geht auch mit GDI+ Stichwort: FlipRotatePicture

Nehme ich auch, wenn es gut ist. Ich habe hier im Forum mal nachgesehen und mir die gdiplus.zip von hier herunter geladen. Die Dateien aus dem Archiv-Verzeichnis pas habe ich nach lib kopiert und dann die Datei ProjectGroup.bpg geöffnet. Jetzt bekomme ich diese Fehlermeldung. Ich habe an anderer Stelle gefunden, man solle eine vorhandene DirectDraw.pas überschreiben. Die habe ich aber nicht. Ferner soll man sich eine aktuelle JEDI.inc besorgen.

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...

mkinzler 5. Mai 2009 15:29

Re: Grenzen von PlgBlt
 
Zitat:

Kann ich da jede beliebige nehmen?
Am Besten eine aktuelle.

EWeiss 5. Mai 2009 15:55

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

Schwedenbitter 5. Mai 2009 16:32

Re: Grenzen von PlgBlt
 
Liste der Anhänge anzeigen (Anzahl: 1)
Zitat:

Zitat von EWeiss
Habe
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

Danke es klappt.

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

EWeiss 5. Mai 2009 16:41

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

Schwedenbitter 5. Mai 2009 17:10

Re: Grenzen von PlgBlt
 
Zitat:

Zitat von EWeiss
Lade die DLL dynamisch und kopiere nur den teil in dein Projekt den du verwendest.

Ich habe leider keine Ahnung, wie das geht, schaue mir aber gern nochmal die Uhr an. Zunächst muss ich das mit dem Drehen erstmal grundsätzlich hinbekommen. Das andere ist dann Kosmetik.

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

EWeiss 5. Mai 2009 17:14

Re: Grenzen von PlgBlt
 
GdipCreateBitmapFromHBITMAP oder umgekehrt GdipCreateHBITMAPFromBitmap

Kann dir nur anraten mein Beispiel anzuschauen da ist alles drin ;)

gruss Emil

Schwedenbitter 5. Mai 2009 22:25

Re: Grenzen von PlgBlt
 
Zitat:

Zitat von EWeiss
GdipCreateBitmapFromHBITMAP oder umgekehrt GdipCreateHBITMAPFromBitmap

Kann dir nur anraten mein Beispiel anzuschauen da ist alles drin ;)

gruss Emil

Ich hatte es befürchtet. Ich bin Gelegenheitsprogrammierer und aus diesem Grunde sprach ich auch von einfach. Das alles ist das Gegenteil von Einfach. Ich staune, dass auch hier im Forum manche Fragen nicht beantwortet wurden und sich keiner mehr rührt. Vermutlich wissen alle außer mir die Antwort.

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 hier zusammen gesucht.
Delphi-Quellcode:
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.
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:
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

Blup 6. Mai 2009 08:41

Re: Grenzen von PlgBlt
 
Hab mal schnell was geschrieben:
Delphi-Quellcode:
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;
Edit: Hoffe es ist einfach genug. :wink:

Schwedenbitter 6. Mai 2009 13:55

Re: Grenzen von PlgBlt
 
Zitat:

Zitat von Blup
Hab mal schnell was geschrieben:
Edit: Hoffe es ist einfach genug. :wink:

Ich bedaure, es nicht zu verstehen. Aber das für mich wichtige funktioniert. Nur nebenbei: Das Drehen um 180° klappt bei mir nicht. Das brauche ich aber auch nicht. Jedenfalls ist es die schnellste Routine, die ich probiert habe und das sind immerhin 4 an der Zahl und sie benutzt neben Assembler keine externen Funktionen. 3 Routinen funktionieren ganz gut und 1 (PlgBlt) klappt nicht mit großen Bildern <-- meine Ausgangsfrage.

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

EWeiss 6. Mai 2009 14:12

Re: Grenzen von PlgBlt
 
Zitat:

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 ...
Ja es ist nicht einfach habe auch sehr viel lesen müssen.
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

Schwedenbitter 6. Mai 2009 18:01

Re: Grenzen von PlgBlt
 
Liste der Anhänge anzeigen (Anzahl: 1)
Zitat:

Zitat von EWeiss
Ja es ist nicht einfach habe auch sehr viel lesen müssen.
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

Dass es für Delphi nur wenig Unterstützung gibt, habe ich schon festgestellt. VB kann ich leider nicht und habe auch nicht die Zeit, mich da einzuarbeiten. Die VB-Anleitungen habe ich auch gefunden. Aber es ist sehr schwer, das nach Delphi zu übertragen.

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:
GDIPBitmap:=TGPBitmap.Create(Image1.Picture.Bitmap.Handle,
                             Image1.Picture.Bitmap.Palette);
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?

Gruß und Danke für die Vorschlage, Hilfen und Ermunterungen

Alex

Blup 7. Mai 2009 08:03

Re: Grenzen von PlgBlt
 
Zitat:

Zitat von Schwedenbitter
Nur nebenbei: Das Drehen um 180° klappt bei mir nicht.

Seltsam, bei mir funktioniert auch das fehlerlos.
Habs auch mit deiner großen Bitmap probiert.
Was genau klappt den nicht, bzw. wie sieht das Ergebnis aus?

Schwedenbitter 22. Nov 2010 14:02

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:
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';
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 progdigy übernommen.
Und so sollte das dann von mir aufgerufen werden:
Delphi-Quellcode:
Procedure TMainForm.BtnRotateClick(Sender: TObject);
Var
  Stat      : GPStatus;
  tmp      : HBitmap;
Begin
  tmp:=Image1.Picture.Bitmap.Handle;
  Stat:=GdipImageRotateFlip(@tmp, Rotate90FlipNone);
  ShowMessage(StatusText[Stat]);
End;
TImage.Picture.Bitmap.Handle ist doch vom Typ HBITMAP. Ist das eine anderes HBITMAP als es GDI+ benutzt?
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

Schwedenbitter 22. Nov 2010 17:23

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:
GdipCreateBitmapFromHBITMAP()
. Der Status passt und der Pointer auf das Image ist nicht mehr
Delphi-Quellcode:
nil
.

Allerdings erhalt ich nun beim Aufruf von
Delphi-Quellcode:
GdipImageRotateFlip
als Status-Rückmeldung
Delphi-Quellcode:
InvalidParameter
wobei folgendes definiert ist:
Delphi-Quellcode:
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;
Auch das stammt nicht von mir, sondern ist ein Ausschnitt aus der von mir bereits zitierten Unit.

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.

Schwedenbitter 22. Nov 2010 23:15

AW: Re: Grenzen von PlgBlt
 
Ich antworte nun mal selbst:

ich habe es mit den Funktionen hinbekommen. Offenbar gelten die Grenzen von
Delphi-Quellcode:
PlgBlt()
bedauerlicher Weise auch für
Delphi-Quellcode:
GdipImageRotateFlip()
. 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.
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 den Code von Blup so aufbohre, dass er auch für Bilder mit pf24bit funktioniert.

Gruß, Alex

Bummi 22. Nov 2010 23:33

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