| 
| Autor | Beitrag |  
| hRb 
          Beiträge: 294
 Erhaltene Danke: 12
 
 
 
 
 | 
Verfasst: So 14.09.25 21:35 
 
Man sollte meinen, dass nach vielen Jahren Compilerentwicklung die unterschiedlichen jpg-Formate korrekt erkannt werden. Dies scheint bei der Vielzahl der Kamerahersteller und vielfältigen Möglichkeiten wie jpg-Header aussehen können nicht der Fall.
 Ich habe ein Programm mit dem Bilder angezeigt werden (Diabetrachter). In aller Regel jpg-Dateien.
 Nun erhalte ich Bilder, die mit einem iPhone aufgenommen wurden und muss feststellen, dass hochkant-fotografierte Bilder nicht automatisch gedreht werden.
 Mein Code:
 		                       Delphi-Quelltext 
 									| 1:2:
 3:
 4:
 
 | usesWinapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
 Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.ExtCtrls, Vcl.Grids,
 Vcl.Imaging.jpeg;
 |  												| 1:2:
 3:
 4:
 5:
 6:
 7:
 8:
 9:
 10:
 11:
 12:
 13:
 14:
 15:
 16:
 17:
 18:
 19:
 20:
 21:
 22:
 23:
 24:
 25:
 26:
 27:
 28:
 29:
 30:
 31:
 32:
 
 | procedure TForm4.FormShow(Sender: TObject);var jpg: TJPEGImage;
 FiName: string;     breite,hoehe: Integer;
 Begin
 ... ... ...
 Form4.Image1.Picture.LoadFromFile(FiName);  end;
 
 procedure TForm1.GrossbildStartMitRandClick(Sender: TObject);
 begin     Form4.BorderStyle := bsSizeable;
 Form4.FormStyle := fsNormal;
 Form4.Windowstate := wsMaximized;
 Form4.Show;
 Form4.SetFocus;
 end;
 
 procedure TForm1.GrossbildStartOhneRandClick(Sender: TObject);
 begin     Form4.BorderStyle := bsNone;
 Form4.FormStyle := fsStayOnTop;
 Form4.BoundsRect := Monitor.BoundsRect;
 Form4.Show;
 Form4.SetFocus;
 end;
 |  Leider bringt mich die Bild-Vorababfrage nach Höhe und Breite auch nicht weiter, denn selbst bei Hochkant-Foto ist Breite > Hoehe. Auf Exit-Analyse habe ich jedoch keine Lust.
 Frage: wer kann mir Code liefern, der bei allen Kameras/Handys funktioniert. 
 PS: arbeite mit Delphi RAD 12 (vor 3 Tagen installiert) |  |  |  
| Th69 
          
  Beiträge: 4799
 Erhaltene Danke: 1059
 
 Win10
 C#, C++ (VS 2017/19/22)
 
 | 
Verfasst: Mo 15.09.25 10:49 
 
	  |  hRb hat folgendes geschrieben  : |  	  | Auf Exit-Analyse habe ich jedoch keine Lust. | 
 Du meinst sicherlich: Exif ;- )
 Ohne diese wirst du aber nicht auskommen, da die Orientierung dort gespeichert ist, s. z.B. die Erklärung in JPEG Image Orientation and Exif .
 PS: Dein 2. Thema habe ich gelöscht (anscheinend wolltest du editieren) und das neuere hier belassen. |  |  |  
| hRb  
          Beiträge: 294
 Erhaltene Danke: 12
 
 
 
 
 | 
Verfasst: Mo 15.09.25 12:23 
 
Sorry, ja natürlich Exif! 
 	  | Zitat: |  	  | Ohne diese wirst du aber nicht auskommen, da die Orientierung dort gespeichert ist | 
 Aber muss denn jeder das Rad neu erfinden? Gibt es keine fertige Routine die besser ist als LoadfromFile?. Meine Canon-Bilder werden übrigens korrekt automatisch gedreht. Die Beschäftigung mit dem jpg-Header zeigt mir eine große Spielwiese für Hersteller. Ich will doch "nur" ein Bild anzeigen", nicht bearbeiten, nicht speichern. Das sollte doch im Standard sein.
 Übrigens: es gibt kaum ein Codebeispiel das ich nicht versucht habe. Keines kann ich fehlerfrei compilieren. Entweder unbekannter Typ, keine Angabe zur uses, Lazerus-Compiler notwendig, etc... 
 Natürlich kenne ich Irfan und verwende ihn auch selbst. Leider wird heute oft nicht mehr fotografiert, sondern geknippst. Eine Bilderflut und selten wird gelöscht. Der Vorteil meines Bildbetrachters ist: er lädt die Bilder eines oder mehrerer Verzeichnisse in eine Stringgridliste und parallel in ein Listview. Dort kann - wenn gewünscht - sortiert werden und im Stringgrid wird markiert was später als Großbild angezeigt werden soll. Alles Bestens, selbst die iPhonebilder in der Vorschau - nur eben nicht mit Loadfromfile(nnn.jpg). Bin ich der Einzige der Bilder anzeigen will? |  |  |  
| Gausi 
          Beiträge: 8549
 Erhaltene Danke: 478
 
 Windows 7, Windows 10
 D7 PE, Delphi XE3 Prof, Delphi 10.3 CE
 
 | 
Verfasst: Di 16.09.25 12:13 
 
Der Punkt ist ja, dass man ein Bild im JPEG-Format auf zwei Arten speichern kann, und beides hat Vor- und Nachteile.
 Einige Hersteller drehen die Bildinformationen direkt, wenn der Anwender die Kamera um 90° dreht. Andere schreiben diese Information nur in die Exif-Daten, so dass ein Bildbetrachter entscheiden kann, ob das Bild "original" oder "gedreht" angezeigt werden soll.
 Die in Delphi eingebaute Funktion TGraphic.LoadfromFile (bzw. die Ableitung in TJpegImage)) scheint die Exif-Daten zu ignorieren und lädt das Bild so, wie es die Kamera abgespeichert hat. Wenn man Jpeg-spezifische Dinge unterstützen möchte, muss man das halt selber machen. Gibt es auch bestimmt schon irgendwo. 
 Die Exif-Daten auslesen sollte keine Zauberei sein. Aufpassen muss man ggf. wenn man das gedrehte Bild nicht nur anzeigen, sondern auch speichern möchte. Das sollte nämlich ohne den Umweg über TBitmap o.ä. gehen, sondern direkt auf den JPEG-Daten, damit das verlustfrei abläuft. Das ist wohl zumindest dann möglich, wenn die Ausmaße des Bildes ein Vielfaches von 8 oder 16 sind.
 Ein weiterer Vorteil, wenn du Exif-Daten benutzen würdest: Soweit ich weiß können darin auch Thumbnails enthalten sein. Wenn man diese für die Übersichts-Liste nutzt, dürfte das die Performance deines Betrachters deutlich steigern - denn dann müssen nicht dutzende Megapixel-Bilder geladen werden, sondern nur die kleinen Vorschaubildchen.  _________________ We are, we were and will not be.
 Für diesen Beitrag haben gedankt: Th69
 |  |  |  
| hRb  
          Beiträge: 294
 Erhaltene Danke: 12
 
 
 
 
 | 
Verfasst: Mi 17.09.25 02:05 
 
Ok, bin ja schon seit einiger Zeit dran Exif-Daten zu lesen und auszuwerten.
 1. Th69 hat einen Link geschickt, der zu einem Codebeispiel führt. Funktioniert aber nicht und scheint uralt zu sein. Mit BlockRead werden immer 12 Byte gelesen. Sehe ich mir jpg-Bilder im Hex-Editer an, ergibt dies überhaupt keinen Sinn. Ich hänge den Code mal unten an. Je nach Kamera sind die Blöcke unterschiedlich lang, d.h. man muss die genaue Header-Struktur kennen. Wo gibts eine übersichtliche Beschreibung?
 2. Gibt es in RAD 12 keine uses z.B. Vcl.Exif um Info zu lesen?
 3. Im iPhone-Bild steht an der Stelle wo üblich Exif steht JFIF. Scheint auch eine Variante der Jpeg-Norm zu sein.
 Möchte ja schon die Exif-Daten auswerten, hoffte nur auf einige fertige Routinen um die Info-Daten zu lesen. (nochmals: nicht schreiben). Alles sehr komplex für mich.
 Gibt es noch etwas was ich noch nicht kenne? Suche schon lange und finde nirgends brauchbaren Code.
 Danke für Geduld. hRb
 Exif-Unit-Code von einem unbekannten Japaner
 												| 1:2:
 3:
 4:
 5:
 6:
 7:
 8:
 9:
 10:
 11:
 12:
 13:
 14:
 15:
 16:
 17:
 18:
 19:
 20:
 21:
 22:
 23:
 24:
 25:
 26:
 27:
 28:
 29:
 30:
 31:
 32:
 33:
 34:
 35:
 36:
 37:
 38:
 39:
 40:
 41:
 
 | unit Unit1;
 interface
 
 uses
 Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
 Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.ExtCtrls,
 Exif;
 
 type
 TForm1 = class(TForm)
 Panel1: TPanel;
 Button1: TButton;
 OpenDialog1: TOpenDialog;
 Memo1: TMemo;
 procedure Button1Click(Sender: TObject);
 private
 
 public
 
 end;
 
 var
 Form1: TForm1;
 Daten: Texif;
 
 implementation
 
 {$R *.dfm}
 
 procedure TForm1.Button1Click(Sender: TObject);
 
 begin
 Daten:= TExif.Create;
 Memo1.Clear;
 opendialog1.Execute;
 Daten.ReadFromFile(opendialog1.FileName);
 Memo1.Lines.Add('fertig');
 end;
 
 end.
 |  //========================
 												| 1:2:
 3:
 4:
 5:
 6:
 7:
 8:
 9:
 10:
 11:
 12:
 13:
 14:
 15:
 16:
 17:
 18:
 19:
 20:
 21:
 22:
 23:
 24:
 25:
 26:
 27:
 28:
 29:
 30:
 31:
 32:
 33:
 34:
 35:
 36:
 37:
 38:
 39:
 40:
 41:
 42:
 43:
 44:
 45:
 46:
 47:
 48:
 49:
 50:
 51:
 52:
 53:
 54:
 55:
 56:
 57:
 58:
 59:
 60:
 61:
 62:
 63:
 64:
 65:
 66:
 67:
 68:
 69:
 70:
 71:
 72:
 73:
 74:
 75:
 76:
 77:
 78:
 79:
 80:
 81:
 82:
 83:
 84:
 85:
 86:
 87:
 88:
 89:
 90:
 91:
 92:
 93:
 94:
 95:
 96:
 97:
 98:
 99:
 100:
 101:
 102:
 103:
 104:
 105:
 106:
 107:
 108:
 109:
 110:
 111:
 112:
 113:
 114:
 115:
 116:
 117:
 118:
 119:
 120:
 121:
 122:
 123:
 124:
 125:
 126:
 127:
 128:
 129:
 130:
 131:
 132:
 133:
 134:
 135:
 136:
 137:
 138:
 139:
 140:
 141:
 142:
 143:
 144:
 145:
 146:
 147:
 148:
 149:
 150:
 151:
 152:
 153:
 154:
 155:
 156:
 157:
 158:
 159:
 160:
 161:
 162:
 163:
 164:
 165:
 166:
 167:
 168:
 169:
 170:
 171:
 172:
 173:
 174:
 175:
 176:
 177:
 178:
 179:
 180:
 181:
 182:
 183:
 184:
 185:
 186:
 187:
 188:
 189:
 190:
 191:
 192:
 193:
 194:
 195:
 196:
 197:
 198:
 199:
 200:
 201:
 202:
 203:
 204:
 205:
 206:
 207:
 208:
 209:
 210:
 211:
 212:
 213:
 214:
 215:
 216:
 217:
 218:
 219:
 220:
 221:
 222:
 223:
 224:
 225:
 226:
 227:
 228:
 229:
 230:
 231:
 232:
 233:
 234:
 235:
 236:
 237:
 238:
 239:
 240:
 
 | unit Exif;
 interface
 
 uses
 Classes, SysUtils;
 
 type
 TExif = class(TObject)
 private
 FImageDesc          : String;           FMake               : String;           FModel              : String;           FOrientation        : Byte;             FOrientationDesk    : String;           FCopyright          : String;           FValid              : Boolean;          FDateTime           : String;           FDateTimeOriginal   : String;           FDateTimeDigitized  : String;           FUserComments       : String;
 f                   : File;
 idfp                : Cardinal;
 function ReadValue(const Offset, Count: Cardinal): String;
 procedure Init;
 public
 constructor Create;
 procedure ReadFromFile(const FileName: AnsiString);
 
 property ImageDesc: String read FImageDesc;
 property Make: String read FMake;
 property Model: String read FModel;
 property Orientation: Byte read FOrientation;
 property OrientationDesk: String read FOrientationDesk;
 property Copyright: String read FCopyright;
 property Valid: Boolean read FValid;
 property DateTime: String read FDateTime;
 property DateTimeOriginal: String read FDateTimeOriginal;
 property DateTimeDigitized: String read FDateTimeDigitized;
 property UserComments: String read FUserComments;
 end;
 
 implementation
 uses unit1;
 
 type
 TMarker = record
 Marker   : Word;          Len      : Word;          Indefin  : Array [0..4] of Char;     Pad      : Char;        end;
 
 TTag = record
 TagID   : Word;           TagType : Word;           Count   : Cardinal;       OffSet  : Cardinal;     end;
 
 TIFDHeader = record
 pad          : Byte;     ByteOrder    : Word;     i42          : Word;     IFD0offSet   : Cardinal;     Interoperabil: Byte;
 end;
 
 function TExif.ReadValue(const Offset, Count: Cardinal): String;
 var fp: LongInt;
 i: Word;
 begin
 SetLength(Result,Count);
 fp:=FilePos(f);   Seek(f, Offset);
 try
 i:=1;
 repeat
 BlockRead(f,Result[i],1);
 inc(i);
 until (i>=Count) or (Result[i-1]=#0);
 if i<=Count then Result:=Copy(Result,1,i-1);
 except
 Result:='';
 end;
 Result:=TrimRight(Result);
 Form1.Memo1.Lines.Add(Result);
 Seek(f,fp);     end;
 
 procedure TExif.Init;
 begin
 
 idfp:=0;
 
 FImageDesc:='';
 FMake:='';
 FModel:='';
 FOrientation:=1;
 FOrientationDesk:='Normal';
 FDateTime:='';
 FCopyright:='';
 FValid:=False;
 FDateTimeOriginal:='';
 FDateTimeDigitized:='';
 FUserComments:='';
 end;
 
 constructor TExif.Create;
 begin
 Init;
 end;
 
 procedure TExif.ReadFromFile(const FileName: AnsiString);
 const ori: Array[1..8] of String=
 ('Normal','Mirrored',
 'Rotated 180','Rotated 180, mirrored',
 'Rotated 90 left, mirrored',
 'Rotated 90 right',
 'Rotated 90 right, mirrored',
 'Rotated 90 left');
 var j: TMarker;
 idf: TIFDHeader;
 off0: Cardinal;   tag: TTag;
 i: Integer;
 SOI: Word;
 begin
 if not FileExists(FileName) then exit;
 Init;
 
 AssignFile(f,FileName);
 reset(f,1);
 
 BlockRead(f,SOI,2);
 if SOI=$D8FF then
 begin     BlockRead(f,j,9);
 
 if j.Marker=$E0FF then begin       Seek(f,20);       BlockRead(f,j,9);
 end;
 
 if j.Marker=$E1FF then
 begin       FValid:=True;               off0:=FilePos(f)+1;         BlockRead(f,idf,11);
 i:=0;
 repeat
 inc(i);
 BlockRead(f,tag,12);
 if tag.TagID=$010E
 then FImageDesc:=ReadValue(tag.OffSet+off0,tag.Count);
 if tag.TagID=$010F
 then FMake:=ReadValue(tag.OffSet+off0,tag.Count);
 if tag.TagID=$0110
 then FModel:=ReadValue(tag.OffSet+off0,tag.Count);
 if tag.TagID=$8769
 then idfp:=Tag.OffSet;                 if tag.TagID=$0112 then
 begin
 FOrientation:=tag.OffSet;
 if tag.OffSet in [1..8] then
 FOrientationDesk:=ori[tag.OffSet]
 else FOrientationDesk:='Unknown';
 end;
 if tag.TagID=$0132
 then FDateTime:=ReadValue(tag.OffSet+off0,tag.Count);
 if tag.TagID=$8298
 then FCopyright:=ReadValue(tag.OffSet+off0,tag.Count);
 until (i>11);
 
 if idfp>0 then begin
 Seek(f,idfp+12+2);        i:=0;
 repeat
 inc(i);
 BlockRead(f,tag,12);
 
 
 if tag.TagID=$9003
 then FDateTimeOriginal:=ReadValue(tag.OffSet+off0,tag.Count);
 if tag.TagID=$9004
 then FDateTimeDigitized:=ReadValue(tag.OffSet+off0,tag.Count);
 if tag.TagID=$9286
 then FUserComments:=ReadValue(tag.OffSet+off0,tag.Count);
 until (i>23);
 end;
 end;
 end;
 CloseFile(f);
 end;
 
 end.
 |  |  |  |  
| hRb  
          Beiträge: 294
 Erhaltene Danke: 12
 
 
 
 
 | 
Verfasst: Mi 17.09.25 02:10 
 
	  | Zitat: |  	  | Die Exif-Daten auslesen sollte keine Zauberei sein. | 
 Wie aus dem Text ersichtlich: Für mich schon. |  |  |  
| jaenicke 
          Beiträge: 19326
 Erhaltene Danke: 1749
 
 W11 x64 (Chrome, Edge)
 Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
 
 | 
Verfasst: Mi 17.09.25 07:00 
 
Wie wäre es denn mit dieser Bibliothek?
github.com/sasgis/ccr-exif |  |  |  
| Holgerx 
          Beiträge: 66
 Erhaltene Danke: 27
 
 Win95 - Win11 / MSServer2000 - MSServer2019
 Delphi 6pro / XE4
 
 | 
Verfasst: Fr 19.09.25 22:36 
 
Hmm..
 Unter Windows kannst Du auch GDI nutzen, um Bilder zu rotieren.
 Hiermit kann ein Foto aus dem iPhone anhand der Ausrichtung rotiert werden unter Verwendung der Transform Möglichkeit.
 Danach ist die Orientierung 0 und das Bild wird von jedem (auch Delphi) Bildbetrachter (ohne EXIF) korrekt angezeigt.
 												| 1:2:
 3:
 4:
 5:
 6:
 7:
 8:
 9:
 10:
 11:
 12:
 13:
 14:
 15:
 16:
 17:
 18:
 19:
 20:
 21:
 22:
 23:
 24:
 25:
 26:
 27:
 28:
 29:
 30:
 31:
 32:
 33:
 34:
 35:
 36:
 37:
 38:
 39:
 40:
 41:
 42:
 43:
 44:
 45:
 46:
 47:
 48:
 49:
 50:
 51:
 52:
 53:
 54:
 55:
 56:
 57:
 58:
 59:
 60:
 61:
 62:
 63:
 64:
 65:
 66:
 67:
 68:
 69:
 70:
 71:
 72:
 73:
 74:
 75:
 76:
 77:
 
 | function GDIRotateToNormal(const AFileName : WideString):boolean;var
 GPImage: TGPImage;
 pPropItem: PPropertyItem;
 BufferSize: Cardinal;
 Orientation: WORD;
 
 tmpFilename : string;
 
 encoderClsid: TGUID;
 tmpSaveOK : Boolean;
 EncoderParams: TEncoderParameters;
 EncoderTransformValue : ULONG; begin
 Result := False;
 if FileExists(AFileName) then begin
 
 tmpSaveOK := False;
 
 GPImage := TGPImage.Create(AFileName);
 try
 BufferSize := GPImage.GetPropertyItemSize(PropertyTagOrientation);
 if BufferSize > 0 then
 begin
 GetMem(pPropItem, BufferSize);
 try
 GPImage.GetPropertyItem(PropertyTagOrientation, BufferSize, pPropItem);
 
 Orientation := PWORD(pPropItem.value)^;
 
 EncoderTransformValue := 0;
 
 case Orientation of
 3: EncoderTransformValue := Ord(EncoderValueTransformRotate180);
 6: EncoderTransformValue := Ord(EncoderValueTransformRotate90);
 8: EncoderTransformValue := Ord(EncoderValueTransformRotate270);
 end;
 if EncoderTransformValue > 0 then begin
 
 SetImageOrientation(GPImage, 1);
 
 GetEncoderClsid('image/jpeg',encoderClsid);
 
 EncoderParams.Count := 1;
 EncoderParams.Parameter[0].NumberOfValues := 1;
 EncoderParams.Parameter[0].Guid   := EncoderTransformation;
 EncoderParams.Parameter[0].Type_  := EncoderParameterValueTypeLong;
 EncoderParams.Parameter[0].Value  := @EncoderTransformValue;
 
 tmpFilename := ChangeFileExt(AFileName, '.$$$');
 
 tmpSaveOK := (GPImage.Save(tmpFilename, encoderClsid, @EncoderParams) = OK);
 end;
 Result := True;
 finally
 FreeMem(pPropItem);
 end;
 end;
 finally
 GPImage.Free
 end;
 
 if tmpSaveOK then begin
 if DeleteFile(AFileName)
 then RenameFile(tmpFilename,AFileName)
 else DeleteFile(tmpFilename);
 end;
 
 end;
 end;
 |  |  |  |  
| hRb  
          Beiträge: 294
 Erhaltene Danke: 12
 
 
 
 
 | 
Verfasst: Mi 22.10.25 01:06 
 
Sorry, wenn ich mich nicht immer zeitnah melde, was nicht bedeutet, dass ich nicht jedem einzelnen Hinweis nachgehe. Danke allen. 
 Allzu lange habe ich mich an der eigenen Auswertung der Exif-Daten versucht. Späte Erkenntnis nach viel Studium und Test: man sollte als Hobbyprogrammierer es tunlichst lassen, insbesondere bei den zahlreichen Möglichkeiten die der Jpeg-Header bietet. Überrascht hat mich, unterscheiden zu müssen, zwischen Motorola- und Intel-Format.
 Das Codebeispiel von Holgerx erscheint mir noch am einfachsten in mein Programm zu integrieren. Tatsächlich liefert die Variable "Orientation" das gewünschte Ergebnis, um den Drehwinkwl des Bildes zu erkennen.
 Leider erhalte ich bei zwei Funktion Compilerfehler (Undeklarierter Bezeichner) . Die Winapi.Windows ist in die uses eingebunden. 
 		                       Delphi-Quelltext 
 									| 1:
 | SetImageOrientation(GPImage, 1);					 |  und
 		                       Delphi-Quelltext 
 									| 1:
 | GetEncoderClsid('image/jpeg',encoderClsid);					 |  Somit kann ich den Restcode zum Speichern des Bildes nicht sinnvoll durchlaufen. Fehlen weitere Unit?
 Da ich das Bild ohnehin nur anzeigen möchte, wäre mir am liebsten nur das geladene Image zu drehen (ohne zu speichern). Im Sinne
 		                       Delphi-Quelltext 
 									| 1:
 |   Img1.RotateFlip(RotateFlipType.Rotate90FlipNone);					 |  Mir fehlt handwerklich das Wissen wie eine Funktion zum Drehen geschrieben werden muss, (finde im Forum immer nur Code um Bitmap zu drehen). 
 Zum anderen habe ich in der Form ein TImage-Object zur Bildanzeige. Obiges Beispiel nutzt aber ein TGPImage. Eine direkte Zuweisung scheitert an ungleichen Typen. Wie löse ich diesen Konflikt?
 Denkbar wäre noch - wenn das Beispiel von Holgerx compilierbar wäre, das Bild zu speichern, anzuzeigen und auf das Rename zu verzichten.
 Kann mir jemand noch hilfreiche Tipps geben? |  |  |  
| hRb  
          Beiträge: 294
 Erhaltene Danke: 12
 
 
 
 
 | 
Verfasst: Mi 22.10.25 02:28 
 
Nachtrag: 
 Nachdem ich in die uses noch  GDIPUTIL hinzugefügt habe, wird 
GetEncoderClsid('image/jpeg',encoderClsid);  compiliert.
 Die Routine SetImageOrientation(GPImage, 1);  liefert weiterhin Fehler.
 Leider finde ich im Internet keine Tipps hierzu
Moderiert von  Th69: Delphi-Tags hinzugefügt |  |  |  
| mandras 
          Beiträge: 434
 Erhaltene Danke: 107
 
 Win 10
 Delphi 6 Prof, Delphi 10.4 Prof
 
 | 
Verfasst: Mi 22.10.25 23:11 
 
Auf die Schnelle fand ich folgendes:
stackoverflow.com/qu...exif-tag-orientation Vielleicht hilft Dir das weiter. |  |  |  
| Holgerx 
          Beiträge: 66
 Erhaltene Danke: 27
 
 Win95 - Win11 / MSServer2000 - MSServer2019
 Delphi 6pro / XE4
 
 | 
Verfasst: Do 23.10.25 08:18 
 
Hi...
 Hier das SetImageOrientation, damit wird nur das PropertyItem gesetzt..
 		                       Delphi-Quelltext 
 									| 1:2:
 3:
 4:
 5:
 6:
 7:
 8:
 9:
 10:
 11:
 12:
 
 | procedure SetImageOrientation(AGPImage: TGPImage; Value: WORD);var
 PropItem : TPropertyItem;
 begin
 if not Assigned(AGPImage) then
 Exit;
 PropItem.Id            := PropertyTagOrientation;
 PropItem.Length        := SizeOf(WORD);
 PropItem.Type_         := PropertyTagTypeShort;
 PropItem.Value         := @Value;
 AGPImage.SetPropertyItem(PropItem);
 end;
 |  Hier zusätzlich eine Routine zum Drehen ohne speichern:
 												| 1:2:
 3:
 4:
 5:
 6:
 7:
 8:
 9:
 10:
 11:
 12:
 13:
 14:
 15:
 16:
 17:
 18:
 19:
 20:
 21:
 22:
 23:
 24:
 25:
 26:
 27:
 28:
 29:
 30:
 31:
 32:
 33:
 34:
 35:
 36:
 37:
 38:
 39:
 40:
 41:
 42:
 43:
 44:
 45:
 46:
 47:
 48:
 49:
 50:
 51:
 52:
 53:
 54:
 55:
 56:
 57:
 58:
 59:
 60:
 61:
 62:
 63:
 64:
 65:
 66:
 67:
 68:
 
 | function GDIRotateToNormalP(const AFileName : WideString; APicture : TPicture):boolean;var
 GPImage: TGPImage;
 GPGraphics: TGPGraphics;
 pPropItem: PPropertyItem;
 BufferSize: Cardinal;
 Orientation: WORD;
 RotateType: TRotateFlipType;
 Bitmap: TBitmap;
 begin
 Result := False;
 if FileExists(AFileName) then begin
 GPImage := TGPImage.Create(AFileName);
 try
 BufferSize := GPImage.GetPropertyItemSize(PropertyTagOrientation);
 if BufferSize > 0 then
 begin
 GetMem(pPropItem, BufferSize);
 try
 GPImage.GetPropertyItem(PropertyTagOrientation, BufferSize, pPropItem);
 Orientation := PWORD(pPropItem.value)^;
 case Orientation of
 1: RotateType := RotateNoneFlipNone;             2: RotateType := RotateNoneFlipX;
 3: RotateType := Rotate180FlipNone;
 4: RotateType := Rotate180FlipX;
 5: RotateType := Rotate90FlipX;
 6: RotateType := Rotate90FlipNone;
 7: RotateType := Rotate270FlipX;
 8: RotateType := Rotate270FlipNone;
 else
 RotateType := RotateNoneFlipNone;           end;
 if RotateType <> RotateNoneFlipNone then
 GPImage.RotateFlip(RotateType);
 finally
 FreeMem(pPropItem);
 end;
 end;
 
 Bitmap := TBitmap.Create;
 try
 Bitmap.Width := GPImage.GetWidth;
 Bitmap.Height := GPImage.GetHeight;
 Bitmap.Canvas.Lock;
 try
 GPGraphics := TGPGraphics.Create(Bitmap.Canvas.Handle);
 try
 GPGraphics.DrawImage(GPImage, 0, 0, GPImage.GetWidth, GPImage.GetHeight);
 APicture.Assign(Bitmap);
 Result := True;
 finally
 GPGraphics.Free;
 end;
 finally
 Bitmap.Canvas.Unlock;
 end;
 finally
 Bitmap.Free;
 end;
 finally
 GPImage.Free
 end;
 end;
 end;
 |  |  |  |  |