Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Sonstige Fragen zu Delphi (https://www.delphipraxis.net/19-sonstige-fragen-zu-delphi/)
-   -   Delphi Bild formatunabhängig 90° drehen (https://www.delphipraxis.net/112640-bild-formatunabhaengig-90%B0-drehen.html)

Nils_13 24. Apr 2008 20:05


Bild formatunabhängig 90° drehen
 
Hi,

gibt es eine Möglichkeit, ein TPicture oder noch besser TCanvas um 90° zu drehen und das ganze ohne TBitmap ? Habe bisher nur bitmapbasierende Methoden gefunden, aber Bitmaps kommen bei mir nicht in Frage.

Corpsman 24. Apr 2008 20:31

Re: Bild formatunabhängig 90° drehen
 
Ist Umständlich, aber

mit Canvas.Pixels bekomst du jeden Wert.

Den kannst du in ein Array speichern ( Im Prionzip ist ein TBitmap, ja nichts anderes ) Dann Drehst dud as Array und kannst mit Canvas.pixels wieder zurückschreiben.

Das ganze hat nur den Hacken das Canvas.pixels eben unheimlich langsam arbeitet, weswegen alle Welt das mit TBitmap macht, denn da hat man Scanline

Nils_13 24. Apr 2008 20:38

Re: Bild formatunabhängig 90° drehen
 
Hm, ist bloß die Frage, ob es schneller ginge, erst ein beliebiges Format zu konvertieren um dann für einen kurzen Moment Scanline zu nehmen.

Corpsman 25. Apr 2008 12:59

Re: Bild formatunabhängig 90° drehen
 
Also wenn wir davon ausgehen das dein Bild 1 M Pixel ist dann auf alle Fälle Ja.

Canvas.Pixels ist wirklich Extrem Langsam.

Im Zweifel probiere es aus.

SirThornberry 25. Apr 2008 13:26

Re: Bild formatunabhängig 90° drehen
 
Mit PlgBlt kannst du ein Bild auf einer Canvas drehen.

Lossy eX 25. Apr 2008 14:07

Re: Bild formatunabhängig 90° drehen
 
Mal anders gefragt. Wieso kommen bei dir Bitmaps nicht in Frage? Denn die Methode zum Zeichnen auf einer Canvas benötigen im Hintergrund eigentlich irgendwo immer ein Bitmap. Bei geladenen JPEGs schmettert es aber bereits die Klasse ab. Also dort kann man das Canvas nur zum Lesen benutzen. Zum Zeichnen braucht man wieder ein Bitmap.

Nils_13 28. Apr 2008 20:53

Re: Bild formatunabhängig 90° drehen
 
Die Lösung ist simpel, man muss aber erstmal drauf kommen. Man zeichnet sich die JPG/PNG/... auf ein TBitmap. Dann kann man mit Hilfe dieses Bitmaps machen was man will, sogar zum Schluss ein TPicture/TGraphic zurückgeben. Diese Funktion lag schon seit langem in fehlerhafter Form auf meiner Platte, sie ist also nur in geringer Form von mir, da sie vorher schon funktionierte. Sie hatte allerdings ein paar Fehler bzw. es fehlten für meine Verwendungszwecke noch Sachen. Die Sache mit dem TPicture als Rückgabewert und dass es überhaupt eine Funktion ist (war vorher eine Prozedur) stammen zum Beispiel von mir. Die Funktion ist auf jeden Fall schnell genug und konvertieren muss man in dem Sinne schon, allerdings unabhängig vom Dateiformat, solange dieses von Delphi unterstützt wird. Der Vorschlag es zu konvertieren kam von eurer Seite schon, allerdings verstand ich ihn etwas falsch, weil ich sofort ein die Funktion JPGtoBMP dachte, die irgendwo in meinen Units noch vor sich hin gammelt. Dann auf jeden Fall ein großes Danke, denn eure Vorschläge waren allesamt gut und ich hätte es auch schnell alles umsetzen können, hätte ich euch sofort verstanden.
Delphi-Quellcode:
type
  TRGBQuad = packed record
    B, G, R, A : Byte;
  end;
  PRGBQuad =^TRGBQuad;
  TRGBarray = Array[0..0] of TRGBQuad;

function Rotate90(const Source : TGraphic) : TPicture;
var P         : PRGBQuad;
    Y, X, H, W : Integer;
    RowOut    : ^TRGBarray;
    SrcBmp    : TBitmap;
begin
  SrcBmp := TBitmap.Create;
  with SrcBmp do
  begin
    PixelFormat := pf32bit;
    Height     := Source.Height;
    Width      := Source.Width;
    Canvas.Draw(0, 0, Source);
  end;

  if Result <> nil then
    Result := TPicture.Create;
  Result.Bitmap.PixelFormat := pf32bit;
  W                   := SrcBmp.Height;
  H                   := SrcBmp.Width;
  Result.Bitmap.Height := H;
  Result.Bitmap.Width := W;
  for Y := 0 to Pred(H) do
  begin
    RowOut := Result.Bitmap.ScanLine[Y];
    P := SrcBmp.ScanLine[Pred(SrcBmp.Height)];
    inc(P, Y);
    for X := 0 to Pred(W) do
    begin
      RowOut[X] := P^;
      inc(P, H);
    end;
  end;
  SrcBmp.Free;
end;

SirThornberry 29. Apr 2008 07:20

Re: Bild formatunabhängig 90° drehen
 
und mit der Nutzung von Scanline ist es wirklich schneller als mit PlgBlt? Kann ich fast nicht glauben.

Schwedenbitter 5. Sep 2008 00:03

Re: Bild formatunabhängig 90° drehen
 
Ich schreibe hier, weil der Thread noch relativ kurz und übersichtlich scheint:

Alle Drehalgorhytmen haben - wenn ich das richtig sehe - gemeinsam, dass sie die Pixel über Scanlines ansprechen, die wiederum aus mehrdimensionale Arrays zusammengesetz sind. Egal welchen Code ich mir hier ansehe, werden die Bilder vor dem Drehen unabhängig von ihrer bisherigen Bittiefe auf 24 oder gar 32 bit gesetzt. Das an sich ist ja auch OK und mir letztlich egal.

Wie bringe ich es fertig, das Bild hinterher wieder Schwarzweiß (pf1bit) zu machen?

Durch das Setzen des Pixelformats klappt es jedenfalls bei mir nicht. Das Bild bekommt dann immer einen Blaustich.

Schwedenbitter 2. Apr 2009 22:22

Re: Bild formatunabhängig 90° drehen
 
Hallo,

ich weiß, dass das Thema schon alt ist. Ich will aber kein neues aufmachen, weil die Frage im Thema den Nagel auf den Kopf trifft.Ich drehe meine Bilder jetzt mit dieser Procedure. Unabhängig von der Farbe nach dem Drehen habe ich noch eine Frage:

Wie drehe ich das Bild gegen den Uhrzeigersinn?

Gruß, Alex

jfheins 2. Apr 2009 22:34

Re: Bild formatunabhängig 90° drehen
 
Die Punkte geben die gewünschte Position an:

Der erste Punkt: Die obere, linke Ecke wird zum ersten Punkt verschoben, die obere rechte Ecke wird zum 2. Punkt verschoben und die untere linke Ecke wird zum dritten Punkt verschoben ;)

Um 90° gegen den Uhrzeigersinn zu rotieren musst du:
Die OL-ecke nach unten verschieben
die OR-Ecke nach links und
die UL-Ecke nach rechts verschieben ;)

Schwedenbitter 2. Apr 2009 23:02

Re: Bild formatunabhängig 90° drehen
 
Zitat:

Zitat von jfheins
Die Punkte geben die gewünschte Position an:

Der erste Punkt: Die obere, linke Ecke wird zum ersten Punkt verschoben, die obere rechte Ecke wird zum 2. Punkt verschoben und die untere linke Ecke wird zum dritten Punkt verschoben ;)

Das hatte ich dem (englischen) Hilfetext bereits entnommen. :gruebel:
Zitat:

Zitat von jfheins
Um 90° gegen den Uhrzeigersinn zu rotieren musst du:
Die OL-ecke nach unten verschieben
die OR-Ecke nach links und
die UL-Ecke nach rechts verschieben ;)

Jetzt habe ich es endlich verstanden! Also so:

Delphi-Quellcode:
Points[0]:=Point(0,tmpBitmap.Width);
Points[1]:=Point(0,0);
Points[2]:=Point(tmpBitmap.Height,tmpBitmap.Width);
Gruß und Dank, Alex

Nachfrage:
Gibt es eine noch schnellere, ähnlich einfache Methode? Für das Drehen eines Bildes mit 1660x2340 braucht mein Celereon M mit 1,86 GHz immerhin ca. 470 ms.

jfheins 3. Apr 2009 08:40

Re: Bild formatunabhängig 90° drehen
 
Du könntest hier mal die vierte probiren, vielleicht ist das etwas schneller: http://www.leunen.com/cbuilder/rotbmp.html ;)

Also das Bitmap kopieren (evtl. mit BitBlt statt Bitmap.Assign) dann auf advanced setzen, dann setworldtransform aufrufen und dann mit bitblt wieder rüberkopieren.

Schwedenbitter 3. Apr 2009 15:52

Re: Bild formatunabhängig 90° drehen
 
Zitat:

Zitat von jfheins
Du könntest hier mal die vierte probiren, vielleicht ist das etwas schneller: http://www.leunen.com/cbuilder/rotbmp.html ;)

Danke. Das werde ich mir mal bei Gelegenheit ansehen!

Jetzt eine weitere Frage: Warum wird das Bild mit diesem Code nicht um 180' gedreht?
Delphi-Quellcode:
Points[0]:=Point(help.Height,help.Width);
Points[1]:=Point(help.Height,0);
Points[2]:=Point(0,help.Width);
Ich bin wieder nach demselben Muster wie beim Drehen nach links bzw. rechts vorgegangen. Die erste Ecke nach ... usw. Und trotzdem klappt es nicht. Ich habe es mehrmals mit Zetteln probiert, wo ich in die Ecken die Zahlen gemahlt hatte.
Geht des nicht mit PlgBlt?

Gruß und schonmal schönes WE, Alex

jfheins 3. Apr 2009 17:21

Re: Bild formatunabhängig 90° drehen
 
Ich tippe darauf:
Delphi-Quellcode:
Points[0]:=Point(help.Height,help.Width);
// Obere, linke Ecke soll nach unten rechts - okay ... aber nur für quadratische Bilder.
// Mein Tipp:
Points[0]:=Point(help.Width,help.Height);

Points[1]:=Point(help.Height,0);
// Obere, rechte Ecke soll nach ... oben rechts??
// Mein Tipp:
Points[1]:=Point(0,help.Height);

Points[2]:=Point(0,help.Width);
// Untere, linke Ecke soll nach ... unten links?
// Mein Tipp:
Points[2]:=Point(help.Width,0);
Guck mal ob das geht ;)

Schwedenbitter 3. Apr 2009 18:03

Re: Bild formatunabhängig 90° drehen
 
Liste der Anhänge anzeigen (Anzahl: 1)
Zitat:

Zitat von jfheins
Ich tippe darauf:
Delphi-Quellcode:
Points[0]:=Point(help.Width,help.Height);
Points[1]:=Point(0,help.Height);
Points[2]:=Point(help.Width,0);

Es geht leider nur fast :wall: :

Generellt dreht er das Bild so tatsächlich um 180'. Aber es gibt dann einen Rand um das Bild, der nicht gedreht wird (obere Zeile und linke Spalte). Da immer die Minimalwerte genommen werden (0 und 0), kann ich mir das nicht erklären.

Außerdem stimmt das mit dem Quadrat auch nur fast. Denn wenn ich das Bild um 180' drehe, hat es meiner Meinung nach dieselben Abmessungen wie das Ausgangsbild. Aus 320x234 werden doch wieder 320x234; nur eben auf dem Kopf. Aus diesem Grunde steht ja sicherheitshalber auch noch
Delphi-Quellcode:
Image1.Picture.Bitmap.Width:=help.Width;
Image1.Picture.Bitmap.Height:=help.Height;
mit dabei, bevor PlgBlt ausgeführt wird...

Woher kommt jetzt wieder der Rand? Soll ich nochmal meinen aktuellen Code hochladen?

Gruß, Alex

Schwedenbitter 20. Apr 2009 17:02

Re: Bild formatunabhängig 90° drehen
 
Für die Drehung um 180° habe ich leider noch keine Lösunmg gefunden, die 100%ig funktioniert. Aber ich habe ein weiteres Problem:

Mein Programm war nur die Übrung für etwas größeres :lol:.
Ich scanne mehrere Bilder mit einem Scanner ein und möchte die dann drehen und strecken bzw. stauchen. Ich habe nun den Code an mein bestehendes Programm angepasst und nun funktioniert er nicht mehr.

Ich scanne die Bilder ein und packe Sie alle in eine TObjectList, wobei ich die Liste mit Bilder.Add(TBitmap.Create); erweitere und die Bilder mit TBitmap(Bilder.Last).Assign(Image); ablege. Wenn der Scanner fertig ist, werden die der Reihe nach wieder ausgelesen und aus der Liste gelöscht. Theoretisch müsste das hier doch klappen:
Delphi-Quellcode:
TBitmap(Bilder.Items[0]).Width:=help.Height;
TBitmap(Bilder.Items[0]).Height:=help.Width;
Points[0]:=Point(0,help.Width);
Points[1]:=Point(0,0);
Points[2]:=Point(help.Height,help.Width);
PlgBlt(TBitmap(Bilder.Items[0]).Canvas.Handle, Points,
       help.Canvas.Handle, 0, 0,
       help.Width, help.Height, 0, 0, 0);
Aber leider bekomme ich nur ein Bild, bei dem sich Höhe und Breite geändert haben. Das ist logisch, weil diese geändert werden. Ich habe die Vermutung, dass PlgBlt nicht (richtig) ausgeführt wird. Bei meinen Versuchen, dieses mittels einer Bool-Variable abzufragen, bekomme ich immer ein positives Ergebnis (=dasselbe wie in meinem Testprogramm, wo es ja klappt).

Was mache ich falsch? :wall:

Schwedenbitter 4. Mai 2009 14:31

Re: Bild formatunabhängig 90° drehen
 
Zitat:

Zitat von Schwedenbitter
Ich habe die Vermutung, dass PlgBlt nicht (richtig) ausgeführt wird. :wall:

Ich habe jetzt genügend herum experimentiert und kann PlgBlt als Übeltäter bezeichnen.
Ich habe mehrere Bilder erzeugt/erzeugen lassen. Ab einer bestimmten Größe klappt PlgBlt nicht mehr. In meinem Fall sind das Bilder mit den Maßen 8,3 x 11,7 Zoll (= DIN A4). Bis exakt 293 dpi (= 2432 x 3428) klappt es prima. Ab den nächstgrößeren Pixeln geht nichts mehr. Es wird nur noch der erste Schritt getan; nämlich die Abmessungen des Bildes vertauscht.
Ich weiß auch nicht, ob das eventuell ein Phänomen von TurboDelphi 2006 sein kann. Ich schließe das fast aus, weil es sich - korrigiert mich, wenn's falsch ist - bei PlgBlt um eine Windows-Funktion handelt.

Kann mir da bitte jemand weiter helfen? Gibt es noch andere Funktionen?

Alex


Alle Zeitangaben in WEZ +1. Es ist jetzt 02:05 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz