Seite 1 von 1

Batch conversation von BMP zu PNG mit Extras

Verfasst: Sonntag 16. Januar 2022, 08:01
von burli
Hi,
ich dachte eigentlich, es wäre einfacher, aber meine Aufgabe hat einige Stolpersteine.

Ich habe folgende Ausgangssituation: ich habe auf mehreren PC identische oder zumindest ähnliche Verzeichnisstrukturen mit Bildern im BMP Format. Die synchronisiere ich auf meinen lokalen PC. Jeder Remote PC muss in ein eigenes Verzeichnis gespeichert werden.

Jetzt möchte ich die Bilder rekursiv nach PNG konvertieren. Das ist noch nicht das eigentliche Problem. Das Problem ist, dass die Verzeichnisstruktur erhalten bleiben soll und die Unterverzeichnisse der Remote PC in ein gemeinsames Verzeichnis zusammengefasst werden. Ich Versuche ein Beispiel.

PC1 hat die Unterverzeichnisse foo1, foo2 und foo3. Jedes dieser Verzeichnisse hat weitere Unterverzeichnisse.

PC2 hat die Unterverzeichnisse foo1, foo2 und foo4 usw

Ich möchte jetzt alle PNG Bilder, die in den foo1 Ordnern gespeichert sind, in einen gemeinsamen foo1 Ordner auf dem lokalen PC konvertieren, egal von welchem Remote PC.

Auf dem Lokalen PC soll es also jeweils nur ein foo1, foo2, foo3 und foo4 Verzeichnis geben, in denen die Bilder von allen Remote PCs gespeichert sind.

Last but not least sollen die original Bilder gelöscht und mit leeren Dateien mit gleichem Dateinamen ersetzt werden, um den Speicherplatz frei zu geben, aber eine weitere Synchronisation zu ermöglichen.

Durch die Verzeichnisse zu wandern und Bilder konvertieren bekomme ich hin. Was mir Probleme macht ist das abspeichern am richtigen Zielort. Klingt eigentlich banal, aber verknotet mir gerade das Hirn. Vermutlich ist es total simpel, aber ich komme nicht drauf.

Wie kann ich den Knoten lösen?

Ach ja, ich möchte das in pure Python machen damit es sowohl unter Windows als auch Linux funktioniert.

Schönen Sonntag

Re: Batch conversation von BMP zu PNG mit Extras

Verfasst: Sonntag 16. Januar 2022, 08:17
von sparrow
Das Problem löst sich, wenn du den Umstand weg lässt, dass es mehrere Clients sind. Es ändert sich ja nur das Basisverzeichnis für die Quelldateien. Die anderen Pfade sind relativ zu diesem. Sowohl zum Basisverzeichnis der Quelle als auch des Ziels.

Re: Batch conversation von BMP zu PNG mit Extras

Verfasst: Sonntag 16. Januar 2022, 08:32
von burli
sparrow hat geschrieben: Sonntag 16. Januar 2022, 08:17 Das Problem löst sich, wenn du den Umstand weg lässt, dass es mehrere Clients sind. Es ändert sich ja nur das Basisverzeichnis für die Quelldateien. Die anderen Pfade sind relativ zu diesem. Sowohl zum Basisverzeichnis der Quelle als auch des Ziels.
Das ist klar. Aber ich stehe wie gesagt gerade komplett auf dem Schlauch. Grundsätzliche Frage: was eignet sich besser? os.walk, glob oder etwas anderes? Und wie erstelle ich nicht vorhandene Verzeichnisse?

Re: Batch conversation von BMP zu PNG mit Extras

Verfasst: Sonntag 16. Januar 2022, 09:58
von burli
Nach einer Tasse Kaffee hat sich der Knoten etwas gelöst, aber mir ist ein anderes Problem aufgefallen, das mein Vorhaben gerade generell sabotiert.

Trotzdem noch einen schönen Sonntag

Re: Batch conversation von BMP zu PNG mit Extras

Verfasst: Sonntag 16. Januar 2022, 11:03
von burli
Der Vollständigkeit halber hier mal meine Lösung. Die Variablennamen müssten eventuell noch etwas überarbeitet werden ;)

Code: Alles auswählen

import os
from PIL import Image
import glob
import re

images = glob.glob('PC?/**/*.bmp', recursive=True)

for img in images:
    # Skip if file is too small
    if os.path.getsize(img) < 10:
        continue

    file = os.path.split(img)

    new_file = (re.sub(r"PC\d+", "PNG",
                file[0]), file[1].replace(".bmp", ".png"))

    # Skip if file already exists
    if os.path.exists(os.path.join(new_file[0], new_file[1])):
        continue

    # Create dir if not exists
    os.makedirs(new_file[0], exist_ok=True)

    # Convert BMP to PNG and save in new dir
    Image.open(img).save(os.path.join(new_file[0], new_file[1]))

    print(os.path.join(new_file[0], new_file[1]))

    # Remove original file and replace with empty file
    os.remove(img)
    os.mknod(img)

Re: Batch conversation von BMP zu PNG mit Extras

Verfasst: Sonntag 16. Januar 2022, 11:30
von Sirius3
Statt `os` und `glob` benutzt man `pathlib.Path`. Und auf pfade geht man auch nicht mit Stringoperationen los, wie `re`oder `replace`, sondern nutzt das, was pathlib.Path so bietet.
Man setzt auch nicht an vier verschiedenen Stellen den Gesamtdateinamen zusammen, sondern speichert das Ergebnis einmal in einer Variable.

Code: Alles auswählen

from pathlib import Path
from PIL import Image

INPUT_PATH = Path('.')
OUTPUT_PATH = Path('PNG')

for pc_path in INPUT_PATH.glob('PC?'):
    for imagefilename in pc_path.glob('**/*.bmp'):
        # Skip if file is too small
        if imagefilename.stat().st_size < 10:
            continue

        relative_imagefilename = imagefilename.relative_to(pc_path)
        new_imagefilename = (OUTPUT_PATH / relative_imagefilename).with_suffix('.png')

        # Skip if file already exists
        if new_imagefilename.exists():
            continue
        new_imagefilename.parent.mkdir(parents=True, exist_ok=True)
        image = Image.open(imagefilename)
        image.save(new_imagefilename)

        print(new_imagefilename)

        # Remove original file and replace with empty file
        imagefilename.write_bytes(b"")

Re: Batch conversation von BMP zu PNG mit Extras

Verfasst: Sonntag 16. Januar 2022, 11:44
von burli
Sirius3 hat geschrieben: Sonntag 16. Januar 2022, 11:30 Statt `os` und `glob` benutzt man `pathlib.Path`. Und auf pfade geht man auch nicht mit Stringoperationen los, wie `re`oder `replace`, sondern nutzt das, was pathlib.Path so bietet.
Man setzt auch nicht an vier verschiedenen Stellen den Gesamtdateinamen zusammen, sondern speichert das Ergebnis einmal in einer Variable.
Das ich mehrfach joine weiß ich. Werde ich bei Gelegenheit ändern. pathlib schaue ich mir auch einmal an, danke.

Re: Batch conversation von BMP zu PNG mit Extras

Verfasst: Sonntag 16. Januar 2022, 14:10
von burli
Nochmal danke für die Überarbeitung. Ich hab noch etwas eingefügt, um ältere Dateien komplett zu löschen.

Code: Alles auswählen

        fname = imagefilename.name
        file_date = fname.split("_")[3]
        year, month, day = file_date[:4], file_date[4:6], file_date[6:]
        now = datetime.datetime.now()
        then = datetime.datetime(int(year), int(month), int(day))
        age = (now - then).days
        if age > 10 and imagefilename.stat().st_size < 10:
            imagefilename.unlink()
            print(fname + " deleted")
            continue
In dem Dateinamen sind alle Infos enthalten und mit "_" getrennt. Das Datum steht im Format yyyymmdd an Position [3]. Da beim überschreiben der Original Datei auch das Datum geändert wird kann ich das nicht mehr verwenden. Deshalb hab ich das so gelöst. Hat da noch jemand einen Verbesserungsvorschlag?

Re: Batch conversation von BMP zu PNG mit Extras

Verfasst: Sonntag 16. Januar 2022, 14:22
von Sirius3
Zum Parsen vom Datum gibt es strptime:

Code: Alles auswählen

file_date = imagefilename.name.split('_')[3]
then = datetime.datetime.strptime(file_date, '%Y%m%d')

Re: Batch conversation von BMP zu PNG mit Extras

Verfasst: Sonntag 16. Januar 2022, 14:46
von burli
Sirius3 hat geschrieben: Sonntag 16. Januar 2022, 14:22 Zum Parsen vom Datum gibt es strptime:

Code: Alles auswählen

file_date = imagefilename.name.split('_')[3]
then = datetime.datetime.strptime(file_date, '%Y%m%d')
Super, danke. Sieht etwas eleganter aus und spart nochmal zwei Zeilen. Das Script tut was es soll. Da kann ich morgen in der Realtest gehen.

Einziges Problem ist, dass die Dateien auf den Remote Rechnern nach einer Weile gelöscht werden und ich darf keine alten und erst recht keine leeren Dateien zurück synchronisieren. Die Synchronisation läuft immer in beide Richtungen, es sei denn ich kann das irgendwie verhindern.

Re: Batch conversation von BMP zu PNG mit Extras

Verfasst: Donnerstag 20. Januar 2022, 09:14
von burli
Ich hab noch eine Frage zu pathlib (bin gerade am Handy, deshalb kein c&p vom Code). Ich möchte alle PNG Dateien in einem Verzeichnis mit OpenCV bearbeiten.

Ich lege mit Path() einen relativen Pfad an, hole mir p.glob("*.PNG") alle Dateien und laufe mit einer for loop über die Liste. So weit, so gut.

Einziges Problem: ich muss mit str() den String aus dem Objekt holen, damit ich die Datei mit cvw.imread() laden kann. Ist das der "offizielle" weg oder gibt es da eine Methode, die einen String liefert? resolve() und absolute() liefern ja auch nur Objekte.

Übersehe ich da was?

Re: Batch conversation von BMP zu PNG mit Extras

Verfasst: Donnerstag 20. Januar 2022, 09:36
von __deets__
Nein. Das ist (noch) so. Bei den meisten der mitgelieferten Bibliotheken gehts inzwischen auch ohne. Aber für Pakete dritter muss man das oft nicht machen.

Re: Batch conversation von BMP zu PNG mit Extras

Verfasst: Donnerstag 20. Januar 2022, 12:07
von burli
Ok, danke. Manche Bibliotheken packen sich den String also selbst aus, andere nicht. Gut zu wissen