_GDIPlus_ImageFixFileExtension

    • Offizieller Beitrag

    Mit dieser Funktion kann man Bilddateien, die eine falsche Dateiendung aufweisen, automatisch umbenennen lassen.

    Die Funktion liest das korrekte Bildformat aus und ändert die Dateiendung entsprechend.

    Die UDF:

    Beispiel:

    AutoIt
    #include '_GDIPlus_ImageFixFileExtension.au3'
    
    $vRet = _GDIPlus_ImageFixFileExtension('d:\test.jpg')
    ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $vRet = ' & $vRet & @CRLF & '>Error code: ' & @error & @CRLF & '>Extended code: ' & @extended & @CRLF) ;### Debug Console
  • Hallo Oscar !

    Danke für die Funktion !

    Bei FileMove verwendest Du ja das Flag 1 (d.h. : $FC_OVERWRITE => bestehende Dateien werden überschrieben).

    Wäre es ggf. sinnvoll einen zusätzlichen Parameter einzufügen, der von bereits bestehenden Dateien eine Sicherheitskopie anlegt ? (Default bleibt natürlich bei OVERWRITE). Das kann sich im Prinzip aber auch jeder selbst einbauen, sofern er diese Option benötigt.

    Ich hoffe, Du gestattest mir einen allgemeinen Hinweis ;).

    Für diejenigen, die sich über die Syntax Return FileMove($sFilename, $sNewFile, 1) ? SetError(0, 0, $sNewFile) : SetError(1, 0, 0) wundern :

    Hierbei handelt es sich um einen sogenannten 'Ternären Operator (engl.: ternary operator) !

    Ist der vor dem Fragezeichen stehende Ausdruck (hier : die Funktion FileMove) = True, dann wird der Teil VOR dem Doppelpunkt (hier SetError(0, 0, $sNewFile) ) ausgewertet bzw. ausgeführt.

    Gibt FileMove hingegen False zurück, dann wird der Teil NACH dem Doppelpunkt (SetError(1, 0, 0)) ausgewertet bzw. ausgeführt.

    Gruß Musashi

    86598-musashi-c64-png

    "Am Anfang wurde das Universum erschaffen. Das machte viele Leute sehr wütend und wurde allenthalben als Schritt in die falsche Richtung angesehen."

    • Offizieller Beitrag

    Wäre es ggf. sinnvoll einen zusätzlichen Parameter einzufügen, der von bereits bestehenden Dateien eine Sicherheitskopie anlegt ?

    Ah, stimmt!

    Ich hab's jetzt aber etwas anders gelöst. Wenn der neue Dateiname bereits existiert, so wird dem neuen Dateinamen ein Zaehler hinzugefügt.

    Das ist mit _WinAPI_PathYetAnotherMakeUniqueName bloß eine Zeile (und ein Include) mehr.

    Geänderte Version in Post#1.

    • Offizieller Beitrag

    Darf ich fragen was du erwartet hast? Alle _WinAPI_* Funktionen (vermutlich bis auf ganz wenige Ausnahmen) benutzen die WinAPI und diese sind nur in Dlls verfügbar.

    So war das nicht gemeint. :)

    Mir ist schon klar, dass die _WinAPI_Funktionen hauptsächlich aus Dll-Calls bestehen.

    Ich wollte darauf hinaus, dass _WinAPI_PathRenameExtension wirklich nur einen Dll-Call ausführt plus eine Error-Zeile.

    Bei vielen _WinAPI-Funktionen werden ja noch diverse Vor- und/oder Nachbereitungen der Parameter/Rückgaben durchgeführt.

    Heißt: Viele der Funktionen bestehen eben nicht nur aus dem Dll-Call.

    Für die zwei Zeilen von _WinAPI_PathRenameExtension wollte ich halt nicht extra das ganze Include einfügen müssen.

  • Achso, okay. Hat sich nur komisch angehört. Die Vorbereitungen kommen ja daher zustande, dass AutoIt eben keine eindeutigen Datentypen hat und alles dann für den Call angepasst werden muss.

    Die Diskussion hatten wir glaube ich schon mal in der SB ob es sich lohnt, ein Include reinzunehmen, wenn man nur eine einzige Funktion braucht.

    Ich glaube es gab sogar eine Option im Compiler die es ermöglicht die benötigten Funktionen aus einem Include zu extrahieren.

    Das müsste /sf im Au3Stripper gewesen sein.

  • Du solltest hier aber noch differenzieren, dass File Type nicht gleich File Type Extension ist... denn *.JPG in *.JPEG oder *.TIF in *.TIFF umzubenennen, ist zumindest für mich nicht erwünscht.

    Ich möchte hier aber auch noch eine Möglichkeit aufzeigen, mit der sich weitaus mehr File Type Extensions korrigieren lassen, als die von GDI+ unterstützen: ExifTool

    Das Tool downloaden, in "exiftool.exe" umbenennen, um es als Command line tool verwenden zu können, und dann kann man die Ausgabe der (gewünschten) Exif-Tags zu den übergebenen Dateien in eine Datei umleiten, die man dann mit AutoIt auswerten kann.

    Hier mal ein Beispiel:

    Code
    :: all but those with no ext
    m:\exiftool.exe -FilePath -FileType -FileTypeExtension -ext "*" --ext . "m:\Meine Bilder" > m:\out.txt

    Nachtrag:

    Diese beiden Dateien sind identisch...

    m:/Meine Bilder/AutoIt.gif und m:/Meine Bilder/AutoIt.bmp

    Hier habe ich lediglich eine Kopie der AutoIt.bmp erstellt und sie in AutoIt.gif umbenannt. Hiervon sollte also keine weitere *.bmp Kopie unter anderem Namen erstellt werden.

    3 Mal editiert, zuletzt von Bitnugger (14. Oktober 2017 um 14:27)

  • Die Diskussion hatten wir glaube ich schon mal in der SB ob es sich lohnt, ein Include reinzunehmen, wenn man nur eine einzige Funktion braucht.

    Sofern ich dabei an die richtige Diskussion denke, ging es um Folgendes :

    Ein User zeigte sich sehr von der Idee begeistert, statt des Includes von UDFs, einfach nur die benötigten Funktionen herauszuschnippeln.

    Er dachte, damit wird alles besser und schneller, weil man ja 'überflüssigen' Balast abwirft.

    Mein Einwand war, dass viele UDFs weitere UDFs (z.B. die ganzen *constant.au3's) einbinden, ohne die viele Funktionen nicht arbeiten können.

    Wie man der Antwort des Users entnehmen konnte, war er sich dieses Risikos gar nicht bewusst ! Wir waren uns daher weitgehend einig, dass ein unbedachtes 'Filetieren' von UDFs durch Gelegenheitsuser eher von Nachteil sei. Zudem spielt das Ganze bei 95% der Skripte bzgl. Laufzeit

    und Dateigröße überhaupt keine Rolle.

    Oscar hingegen weiß genau was er macht, wenn er einen Zweizeiler dupliziert ;). Damit wird den Nutzern seiner Funktion das unnötige Einbinden einer kompletten UDF erspart. In diesem Fall, meiner Meinung nach, absolut vertretbar.

    Gruß Musashi

    86598-musashi-c64-png

    "Am Anfang wurde das Universum erschaffen. Das machte viele Leute sehr wütend und wurde allenthalben als Schritt in die falsche Richtung angesehen."

  • In diesem Fall, meiner Meinung nach, absolut vertretbar.

    Aber wenn es später dazu kommt, dass man weitere Funktionen der WinAPI.au3 benötigt, muss man sich entscheiden ob man die Funktionen kopiert oder die bereits kopierten löscht und dann die gesamte UDF einbindet. Ich hatte das schon mehrmals mit GdiPlus und _GDIPlus_Get/SetPixel.

    Meiner Meinung nach ist das kein guter Stil sich die benötigten Funktionen rauszukopieren, denn das bläht das Hauptscript nur weiter auf.

    Wenn ich beispielsweise aus einer UDF 30 Zeilen Funktionen kopiere, hätte ich mir 27 davon (und die Mühe zum Kopieren) sparen können, indem ich den Au3Stripper verwende.

  • Aber wenn es später dazu kommt, dass man weitere Funktionen der WinAPI.au3 benötigt, muss man sich entscheiden ob man die Funktionen kopiert oder die bereits kopierten löscht und dann die gesamte UDF einbindet. Ich hatte das schon mehrmals mit GdiPlus und _GDIPlus_Get/SetPixel.

    Meiner Meinung nach ist das kein guter Stil sich die benötigten Funktionen rauszukopieren, denn das bläht das Hauptscript nur weiter auf.

    Oscar hat aber nicht die Funktion selbst dupliziert, sondern nur deren Inhalt. Sollte jemand später die gesamte UDF einbinden, dann entsteht kein Konflikt mit ggf. bereits vorhandenen Funktionsnamen.

    Was das Auslösen einzelner Funktionen betrifft, bin ich völlig deiner Meinung !

    Gruß Musashi

    86598-musashi-c64-png

    "Am Anfang wurde das Universum erschaffen. Das machte viele Leute sehr wütend und wurde allenthalben als Schritt in die falsche Richtung angesehen."

    • Offizieller Beitrag

    Du solltest hier aber noch differenzieren, dass File Type nicht gleich File Type Extension ist... denn *.JPG in *.JPEG oder *.TIF in *.TIFF umzubenennen, ist zumindest für mich nicht erwünscht.

    Ah, verdammt!

    Du hast recht, "_GDIPlus_ImageGetRawFormat" gibt nicht die FileExtension zurück.

    Die Abfrage, ob es sich bei der bisherigen um eine korrekte Dateiendung handelt, ist also "suboptimal". :whistling:

    Ich habe die UDF nun noch um eine bessere Abfrage erweitert. Neue Version in Post#1.

    Hier habe ich lediglich eine Kopie der AutoIt.bmp erstellt und sie in AutoIt.gif umbenannt. Hiervon sollte also keine weitere *.bmp Kopie unter anderem Namen erstellt werden.

    Naja, ich denke, dass das übertrieben wäre, jetzt auch noch eine Abfrage auf Gleichheit der Dateien einzubauen.

    Und bezüglich dem ExifTool: eine 2.5KB-Funktion gegen ein 5MB-Programm austauschen? ;)

  • Naja, ich denke, dass das übertrieben wäre, jetzt auch noch eine Abfrage auf Gleichheit der Dateien einzubauen.

    Sind doch nur ein paar Zeilen mehr... ich war mal so frei und habe sie eingebaut.

    Code: Ausgabe
    > _GDIPlus_ImageFixFileExtension(): FileName   = m:\Meine Bilder\AutoIt.tif
    > _GDIPlus_ImageFixFileExtension(): Format     = BMP
    > _GDIPlus_ImageFixFileExtension(): Extensions = *.BMP;*.DIB;*.RLE
    ! _GDIPlus_ImageFixFileExtension(): Diese Dateien sind identisch:
    ! --> Crc32 = 0x831ACA8E  m:\Meine Bilder\AutoIt.tif     - Falsche Dateierweiterung  (wird gelöscht)
    + --> Crc32 = 0x831ACA8E  m:\Meine Bilder\AutoIt.bmp     - Richtige Dateierweiterung (wird behalten)
    @@ Debug(18) : $vRet = m:\Meine Bilder\AutoIt.bmp

    Und bezüglich dem ExifTool: eine 2.5KB-Funktion gegen ein 5MB-Programm austauschen?

    Wer nur die von GDIPlus unterstützten Formate überprüfen möchte, ist mit deiner Funktion bestens bedient... wer möglichst viele Formate überprüfen will, hat mit dem Exiftool eine gute Alternative.

    • Offizieller Beitrag

    Sind doch nur ein paar Zeilen mehr... ich war mal so frei und habe sie eingebaut.

    Ok, ich habe das mal mit übernommen. Danke für das Beispiel! :thumbup:

    Allerdings funktioniert das prüfen auf die Dateiendung mit StringInStr nicht. Wenn man z.B. als Dateiendung nur ".jp" hat (das "g" vergessen), dann wird das mit StringinStr als korrekt angesehen.

    Da bin ich doch bei der Array-Schleife geblieben und die Funktionsnamen habe ich mal eindeutiger gemacht, um Verwechslungen auszuschliessen.

    Neue Version in Post#1.

  • Sehr schön, gefällt mir!

    Allerdings funktioniert das prüfen auf die Dateiendung mit StringInStr nicht. Wenn man z.B. als Dateiendung nur ".jp" hat (das "g" vergessen), dann wird das mit StringinStr als korrekt angesehen.

    Das hat mir keine Ruhe gelassen... muss doch auch als Einzeiler gehen! 8o

    Code
    If StringInStr($__g_aGDIPDecoders[$iFormat][6] & ';', StringRegExpReplace($sFilename & ';', '(?:.+)(\..+;)', '$1')) Then Return SetError(0, 1, $sFilename)

    Ich habe noch ein paar Zeilen geändert... schau es dir einfach mal an.