Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Multimedia (https://www.delphipraxis.net/16-multimedia/)
-   -   GDI+ Delphi Berlin oder höher (https://www.delphipraxis.net/205214-gdi-delphi-berlin-oder-hoeher.html)

Willie1 12. Aug 2020 16:41

GDI+ Delphi Berlin oder höher
 
Hallo Leute,
ich hatte ein altes Programm von mir noch etwas verbessert. War hier lange Thema. Das läuft jetzt alles gut aber noch mit Delphi 2005 auf einem alten Notebook compiliert. (Kann ich sehr schlecht sehen)
Deshalb will ich es auf das neue Delphi portieren (PC mit großem Display) und da prasseln die Fehlermeldungen. Einige habe ich lösen können, das hier nicht. PropertyTagDateTime liefert laut Microsoft-Doku Rückgabe: PropertTagTypeASCII, Count 20. Aber wie das gespeichert ist, wird nicht verraten. Damals habe ich Folgendes gefunden:
Delphi-Quellcode:
  function TGDIExifRead.ExifDateToDateTime(s: string):TDateTime;
    type
      TConvert = packed record                        // Idee von Gerry McGuire
         year: array [1..4] of char; f1:char;
         mon: array [1..2] of Char; f2:char;
         day: array [1..2] of Char; f3:char;
         hr:  array [1..2] of Char; f4:char;
         min: array [1..2] of Char; f5:char;
         sec: array [1..2] of Char;
      end;
      PConvert = ^TConvert;
    begin
    s:=Trim(s);
    if s = '' then
      Result:=-1                                         //kein Datum vorhanden!
    else
      try
        with PConvert( @s[1] )^ do
          Result:=EncodeDate( StrToInt( year ),
                              StrToInt( mon ),
                              StrToInt( day ))
                + EncodeTime( StrToInt( hr ),
                              StrToInt( min ),
                              StrToInt( sec ), 0);
      except
        Result:=0;                                      //ungültiges Datum
      end;
  end;
Hat 12 Jahre funktioniert jetzt bei Delphi Berlin crashed es bei with PConvert()^ Ich benutze GDPAPI, GDPOBJECT und GDPUTIL.

Willie.

DeddyH 12. Aug 2020 17:02

AW: GDI+ Delphi Berlin oder höher
 
Wie sieht es aus, wenn Du explizit Ansi verwendest, also den Parameter als AnsiString und die Record-Felder als AnsiChars?

himitsu 12. Aug 2020 17:06

AW: GDI+ Delphi Berlin oder höher
 
Joar, das beliebte Char statt AnsiChar,
da sich die Daten bestimmt nicht ändern, nur weil der Compiler plötlich WideChar (Unicode) verwendet.


Allerdings passt es hier eigentlich,
denn String geht rein und Char's werden drüber gelegt.
Und ja, AnsiString und AnsiChar würden auch zusammenpassen.

Auch das PACKED ist drin, damit sich nicht plötzlich die Speicherausrichtung ändern könnte.


Jetzt ungeprüft auf einen unbekannt "langen" String loszugehen und das mit einem blinden Try-Except abzufangen ist nicht die feine englische Art,
aber da hier nur gelesen wird und über StrToInt eine gewisse Prüfung enthalten ist, würde ich das mal durchgehen lassen.




Ganz im Ernst, das hier ist ein perfektes Beispiel, um den Debugger zu benutzen.
Schauen was rein geht und wo es knallt, bzw. was nicht stimmt.
Von den Typen her sehe ich jedenfalls kein Problem, also kann es nur an den Daten liegen.

Würde ich diese Programm aber debuggen müssen und es knallt dann ständig, würde ich den Erfinder dieser Funktion garantiert erschlagen.
Delphi-Quellcode:
if (Length(S) = 19 {falls ich mich nicht verzählt hab}) and TryStrToInt(....) and ...

else
  Result := 0;
Und weg mit dem Try-Except-Dreck.




StrToDateTime Delphi-Referenz durchsuchenTryStrToDateTime mit einem FormatSetting.LongDateFormat+LongTimeFormat
oder vielleicht Delphi-Referenz durchsuchenISO8601ToDate ?

Benmik 12. Aug 2020 17:14

AW: GDI+ Delphi Berlin oder höher
 
Delphi-Quellcode:
uses ... , System.SysUtils, System.IOUtils,System.Types,System.StrUtils, GDIPAPI, GDIPOBJ,GDIPUTIL;

...

procedure DatumMitGDIPlus;
Var i:integer;
  DatListe:TStringDynArray;
  GPImage: TGPImage;
  PPropItem: PPropertyItem;
  BufferSize: Cardinal;
  TxtDatum:string;
  Datum:TDateTime;
begin
  DatListe := TDirectory.GetFiles(Verz,'*.jpg');
  For i := 0 to High(Datliste) do begin
    GPImage := TGPImage.Create(DatListe[i]);
    BufferSize := GPImage.GetPropertyItemSize(PropertyTagDateTime);
    If BufferSize > 0 then begin
      GetMem(PPropItem, BufferSize);
      Try
        GPImage.GetPropertyItem(PropertyTagDateTime, BufferSize, PPropItem);
        SetString(TxtDatum, PAnsiChar(PPropItem.value), PPropItem.length - 1);
        Datum := EncodeDate(StrToInt(Copy(TxtDatum, 1, 4)),StrToInt(Copy(TxtDatum, 6, 2)),StrToInt(Copy(TxtDatum, 9, 2))) +
                 EncodeTime(StrToInt(Copy(TxtDatum, 12, 2)),StrToInt(Copy(TxtDatum, 15, 2)),StrToInt(Copy(TxtDatum, 18, 2)), 0);
      Finally
        FreeMem(PPropItem);
      end;
    end;
  end;
end;

himitsu 12. Aug 2020 17:41

AW: GDI+ Delphi Berlin oder höher
 
Zitat:

Zitat von Willie1 (Beitrag 1471723)
crashed es bei with PConvert()^

Also der Compiler knallt?
Und wenn ja, warum nennt niemals irgendwer die Fehlermeldung?

Delphi-Quellcode:
PConvert(Pointer(@s[1]))^

Benmik 12. Aug 2020 17:56

AW: GDI+ Delphi Berlin oder höher
 
Zitat:

Zitat von himitsu (Beitrag 1471728)
..warum nennt niemals irgendwer die Fehlermeldung?

Und warum dem Fehler in einer nicht funktionierenden Prozedur nachjagen, wenn es eine funktionierende gibt?

Willie1 12. Aug 2020 18:13

AW: GDI+ Delphi Berlin oder höher
 
Zitat:

Zitat von himitsu (Beitrag 1471728)
Zitat:

Zitat von Willie1 (Beitrag 1471723)
crashed es bei with PConvert()^

Also der Compiler knallt?
Und wenn ja, warum nennt niemals irgendwer die Fehlermeldung?

Delphi-Quellcode:
PConvert(Pointer(@s[1]))^

EConvertError "m9" ist kein gültiger Integerwert.

Das Andere guck ich mir morgen an. Danke Freunde*innen. Willie.

Benmik 12. Aug 2020 18:26

AW: GDI+ Delphi Berlin oder höher
 
Das Format ist "yyyy:mm:dd hh:mm:ss". Ein "m9" kann darin nicht vorkommen. Nicht diese Routine, sondern das Auslesen des Strings ist falsch. Hast du dir den String denn mal angesehen?

EDIT: Nur für den Fall der Fälle:
Delphi-Quellcode:
if (Length(S) = 19
würde eventuell nach hinten losgehen, da die Puffergröße und damit die Länge des Strings immer 20 Zeichen beträgt, da der String nullterminiert ist.

Willie1 13. Aug 2020 17:29

AW: GDI+ Delphi Berlin oder höher
 
Zitat:

Zitat von DeddyH (Beitrag 1471725)
Wie sieht es aus, wenn Du explizit Ansi verwendest, also den Parameter als AnsiString und die Record-Felder als AnsiChars?

Ihr habt es sofort erkannt. Natürlich AnsiChar, denn schließlich heißt es ja PropertyTagTypeASCII (!). So wird es klappen, äh noch 'ne Frage kann ich bei AnsiString das #0 am Ende weglassen? Gibt es einen Compiler-Schalter, um im Quelltext String als AnsiString zu definieren? Bennik, deinen Source werde ich ausprobieren, danke.
Ich werde mich beim Anpassen meiner ExifRead-Bibliothek sicher nochmal melden müssen. Es gibt viele Propertys mit TypeASCII, TypeRational macht keine Probleme.
Willie.

TurboMagic 13. Aug 2020 20:04

AW: GDI+ Delphi Berlin oder höher
 
Es gibt keinen Stringtyp Compilerschalter.

Delphi hängt automatisch #0 an Strings an um diese leichter
an WinApi Aufrufe übergeben zu können.

himitsu 13. Aug 2020 21:11

AW: GDI+ Delphi Berlin oder höher
 
Jupp, wenn man den String richtig gefüllt hat, dann ist im Inhalt keine #0 mehr drin. :stupid:


Den Compilerschalter kann es leider nicht geben.

Man könnte ja nur lokal, in seiner Unit, den Typ ändern.
Aber die Funktionen betrifft das nicht.

Vorallem in den APIs sind diese ja nicht Überladen, sondern heißen alle anders.
String, PChar und Char in deiner Unit OK,
aber CreateFile wird in einer anderen Unit auf CreateFileW umgeleitet. Und Diese ist vorkompiliert und somit quasi unveränderlich.

Benmik 13. Aug 2020 22:47

AW: GDI+ Delphi Berlin oder höher
 
Du kannst einen String als AnsiString deklarieren:
Delphi-Quellcode:
var AnsiTxt: AnsiString;

Das sollte im Zusammenhang mit GDI+ aber gar nicht nötig sein; bei ASCII - also Property-Typ 2 - solltest du mit
Delphi-Quellcode:
SetString(ZielTxt, PAnsiChar(PPropItem.value), PPropItem.length - 1));
ohne Probleme hinkommen. Mich würde ein Beispiel interessieren, sollte das doch mal nicht der Fall sein.

KodeZwerg 14. Aug 2020 07:24

AW: GDI+ Delphi Berlin oder höher
 
Ich weiß gerade nicht ob per Inception das machbar ist.
Mit Vcl's weiß ich es zu 100pro das es klappt.
Dient mir als Ersatz für "Helper" wenn ich mich immer nur an's original halten möchte.
Eine Unit erstellen wo lediglich "String" als "AnsiString" definiert wird.
Diese Unit dann als letzte in Deinem Projekt einbinden.
Schon ist wieder alles wie vor 20 Jahren, aber ob man das wirklich will ist jedem selbst überlassen.

himitsu 14. Aug 2020 13:37

AW: GDI+ Delphi Berlin oder höher
 
Wie gesagt, es ist egal, denn du kannst nur den Typ in deiner Unit mit einem anderen Typen überdecken,
aber externe Definitionen beeinflusst es nicht.

Abgesehn davon ist String schwachsinniger Weise seit Jahrzehnten immernoch ein resserviertes Wort und da geht Vieles nicht.

Willie1 15. Aug 2020 16:36

AW: GDI+ Delphi Berlin oder höher
 
Ich habe in meiner Bibliothek alle string durch AnsiString, PChar durch PAnsiChar und alle Char durch AnsiChar ersetzt, TstringList bleibt unverändert, und der Compiler meckert bei meinem Testprogramm nicht mehr. Bei Filename habe ich string durch TFilename ersetzt. Jetzt läuft es auch mit dem GDP-Dateien von 2003. Verrenkungen bei string sind also nicht nötig. "Alte Sünden werden nicht vergessen" bei meiner Lösung crasht es bei Bildern vom IPhone, das war und ist immer noch so. Jetzt packt mich der Ehrgeiz auch das will ich lösen.
Delphi-Quellcode:
          else                    //alle anderen
          with PropItem^ do begin
            Move(Value^, RationalBuff, Length);
            R1:=RationalBuff[0];
            R2:=RationalBuff[1];
            s:=Format('%d/%d',[R1,R2]);
            try
            s1:=ShowID(ShowTagStr, GetMetaDataIDString(id), PropID);
            except
              Result:=s;
              Exit;
            end;
            Result:=Format('%s %s',[s1,s])
          end;
Es geht um PropertyItem^.id, der Debugger zeigt eine Cardinal-Zahl an, wenn es klappt und meldet "nicht verfügbarer Wert", wenn es crasht. Die Routine liefert ein richtiges Result und erst beim Verlassen der Funktion gibt es den Zugriffsfehler.
Willie.

himitsu 15. Aug 2020 17:44

AW: GDI+ Delphi Berlin oder höher
 
Was ist RationalBuff?

Bei dem MOVE, könnte man z.B. an ungültige Zeiger und einen Bufferoverflow denken.

Willie1 15. Aug 2020 18:54

AW: GDI+ Delphi Berlin oder höher
 
RationlBuff ist ein Array[0..1] of Integer für Zähler und Nenner. Wie geht das ohne Move, ist mir klar, das das unsicher ist.

Benmik 16. Aug 2020 12:18

AW: GDI+ Delphi Berlin oder höher
 
Es geht hier um den Datentyp 5. Eigentlich soll er 8 Bytes lang sein mit 4 Bytes Zähler und 4 Bytes Nenner. Laut Spezifikation ist er "unsigned", müsste also 2 x Cardinal sein, denn es gibt ihn auch noch mit Vorzeichen als Typ 10.

Es ist aber keineswegs so, dass der Typ 5 immer nur 2 x 4 = 8 Bytes hat, zum Beispiel nicht bei den GPS-Werten. Bei GPSLongitude und GPSLatitude hat er 3 x 8 = 24 Bytes (das ist auch so bei EXIFTool vermerkt). Da könnte es bei deinem iPhone haken, weil es vermutlich GPS-Daten in die JPG schreibt. Daher ist deine Lösung nicht optimal an den Typ 5 angepasst.

Ich mache das ungefähr so (ist jetzt so dahingeworfen):
Delphi-Quellcode:
var Buff:TBytes;
    Zähler,Nenner,DritterWert:Cardinal;
begin
  SetLength(Buff,Length);
  Move(Value^, Buff[0], Length);
  Zähler := PCardinal(@TB[0])^;
  Nenner := PCardinal(@TB[4])^;
  If Length >= 12
    then DritterWert := PCardinal(@TB[8])^;
end;
Der Zusammenbau von GPSLatitude etc. ist auch nicht ganz trivial. Das verdeutlich das Prinzip, vielleicht hilft dir das erstmal weiter.

Willie1 16. Aug 2020 15:50

AW: GDI+ Delphi Berlin oder höher
 
Zitat:

Zitat von Benmik (Beitrag 1471896)
Es geht hier um den Datentyp 5.

Der Zusammenbau von GPSLatitude etc. ist auch nicht ganz trivial. Das verdeutlich das Prinzip, vielleicht hilft dir das erstmal weiter.

Ja, es geht um PropertyTagTypeRational: 2 Zahlen = 4 Bytes für Zähler und Nenner. Ich hatte es mit Move gemacht, vor 15 Jahren konnte ich es nicht besser. Bennik, genau die Geo-Koordinaten haben mich auf diese Idee gebracht, es geht.
Delphi-Quellcode:
  Type
    TRationalBuff = array[0..1] of Integer;
    TPRationalBuff = ^TRationalBuff;

          else                    //alle anderen
          with PropItem^ do begin
//            Move(Value^, RationalBuff, Length);   //löst Fehler bei Apple aus
            RationalBuff := TPRationalBuff(Value)^;
            R1:=RationalBuff[0];
            R2:=RationalBuff[1];
            if R2 > 0 then
              s:=Format('%0.4f',[R1 / R2])
            else
              s:='error';
            s1:=ShowID(ShowTagStr, GetMetaDataIDString(id), PropID);
            Result:=Format('%s %s',[s1,s])
          end;
Die GDP-Dateien habe ich natürlich auch neu kompiliert, da gibt es viele string - Typen, jetzt alle als 16-Bit-String, Kann es da zu Problemen kommen? Ich weiß aus schmerzhafter Erfahrung Test- oder Demoprogramm ist das eine, der Einsatz in einem großen Programm ist das andere. Meine Motivation hatte ich oben erklärt. Willie.

Benmik 16. Aug 2020 17:45

AW: GDI+ Delphi Berlin oder höher
 
Der RationalBuff kann nur 8 Byte aufnehmen, bei GPS sind es aber 24. Mit ihm kommst du also nicht an bestimmte GPS-Daten ran (GPSLongitude, GPSLatitude).

Move an sich ist völlig OK; man kann es auch über eine Pointer-Variable machen, aber dann hat man nicht die Flexibilität von TBytes. Ich meine, es ist immer noch am besten, Length zu messen, TBytes entsprechend zu dimensionieren und danach zu handeln.

Bei den Stringtypen von Typ 7 ist es nicht ganz so einfach, die können laut Spezifikation auch Unicode sein, worauf du mit AnsiChar nicht weiter kommst. Das betrifft vor allem UserComment. Man kann die Strings ruhig bei Delphi-String belassen, muss sich dann aber um die Konvertierungen kümmern.

Ich muss jetzt zum Zug; später komme ich eventuell dazu, etwas zu posten.

Willie1 16. Aug 2020 18:43

AW: GDI+ Delphi Berlin oder höher
 
Hallo Bennik, gute Fahrt, bei der Bahn muss man immer Sorgen haben!

Ich habe versucht mein Projekt von ca. 2008 mit D-Berlin zu kompilieren. Meine eigenen Komponenten zu integrieren war einfach. Aber es ist genauso, wie ich befürchtet hatte. Es knallen die Fehlermeldungen. Besonders eine Bibliothek von 2006 von Gerry McGuire dExif macht Probleme. Er hat wohl sehr tricky programmiert.
Ich muss bei Delphi 2005 bleiben: Trotzdem sind deine Hinweise für mich sehr wichtig. Sind AnsiString, AnsiChar PAnsiChar bei Delphi 2005 schon bekannt oder muss ich die Änderungen wieder zurücknehmen. Das wäre blöd.
Gruß Willie.

Benmik 16. Aug 2020 19:41

AW: GDI+ Delphi Berlin oder höher
 
Jetzt fahre ich 15 km mit dem Rad zum Bahnhof und der Zug fällt aus! So'n Mist. Und kein LTE.

dEXIF wollte ich dir empfehlen, aber ich dachte, du möchtest alles selber machen.

Schau doch mal auf diese Version, die mit Rio 10.3.3 anstandslos funktioniert. Mit dieser Unit brauchst du aber eigentlich überhaupt michts mehr selbst zu machen, was EXIF, betrifft, es ist alles fix und fertig.

Willie1 17. Aug 2020 09:50

AW: GDI+ Delphi Berlin oder höher
 
Zitat:

Zitat von Benmik (Beitrag 1471914)
Jetzt fahre 15 km mit dem Rad zum Bahnhof und der Zug fällt aus! So'n Mist. Und kein LTE.

Ich war viele Jahre Wochenendpendler. Ich sage dir, es stimmt, früher war die Bahn besser!!!

Ich benutze dExif für IPTC-Daten aus zu lesen und zum Schreiben des JPG-Kommentars. An eine neue Version von Gerry McGuire hab' ich nicht gedacht. Willie.

Benmik 17. Aug 2020 16:35

AW: GDI+ Delphi Berlin oder höher
 
Liste der Anhänge anzeigen (Anzahl: 1)
Ich kann nur an dich appellieren, mit Rio 10.3.3 weiterzumachen. Das Allermeiste, was jetzt veröffentlicht wird, setzt auf Sprachfeatures, die mindestens Delphi 2009 voraussetzen. Du musst dir die Arbeit sowieso machen, und so schlimm ist das auch gar nicht.

Das erwähnte dEXIF läuft ohne Probleme unter Rio und nimmt dir fast alle Arbeit ab. Probiere dies:
Delphi-Quellcode:
procedure TesteDEXIF;
var ImgData: TImgData;
    Verz,Datname:string;
begin
  Verz := 'C:\Temp\';
  Datname := 'BLD00405.JPG';
  ImgData := TImgData.Create;
  Try
    If ImgData.ProcessFile(Verz + Datname) and ImgData.HasExif then begin
    end;
  Finally
    ImgData.Free;
  End;
  Application.Terminate;
end;
Alles, was du brauchst, findest du dann in
Delphi-Quellcode:
ImgData.ExifObj
- und noch viel mehr.
Setze mal einen Haltepunkt auf
Delphi-Quellcode:
ImgData.Free;
.
Ich habe dir im Debugger mal beispielhaft DateTimeOriginal geöffnet, mit dem du solche Schwierigkeiten hattest.

Willie1 17. Aug 2020 17:40

AW: GDI+ Delphi Berlin oder höher
 
Hallo Bennik,
dein Tipp mit dExif war Gold wert. Habe ich mir dExif und Co. herunter geladen und die Dateien in meinem Projekt einfach ersetzt und es läuft. Toll!

Wie sieht es mit der Community-Edtion aus, kennst du dich da aus? Natürlich will ich Delphi 2005 abknipsen. Ist ein Sammelsorium von Fehlern!!!
Gruß Willie.

Benmik 17. Aug 2020 19:32

AW: GDI+ Delphi Berlin oder höher
 
Zitat:

Zitat von Willie1 (Beitrag 1471963)
Wie sieht es mit der Community-Edtion aus, kennst du dich da aus? Natürlich will ich Delphi 2005 abknipsen.

Wie meinst du das? Du gehst einfach hierhin, gibst die Daten ein (hoffentlich die richtigen, ähem), dann bekommst du einen Downloadlink und den Lizenzschlüssel per E-Mail. War das deine Frage?

Willie1 18. Aug 2020 16:24

AW: GDI+ Delphi Berlin oder höher
 
Ja! Verträgt die Com-Version mit Starter Edition Berlin? Kann ich sie parallel benutzen. Bei Delphi 2005 und 2006 war das problemlos. W.

Benmik 18. Aug 2020 17:53

AW: GDI+ Delphi Berlin oder höher
 
Ich glaube, das geht. Probiere es doch einfach aus. Ich meiner allerdings, dass es wenig Zweck hat, beide parallel zu benutzen, die sind sich ziemlich ähnlich. Vermutlich meinst du aber für eine Umstellungsphase. Exportiere mit regedit den entsprechenden Zweig von Embarcadero, für alle Fälle.


Alle Zeitangaben in WEZ +1. Es ist jetzt 13:21 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