[PYTHON] Ich habe ein CLI-Tool erstellt, um Bilder in jedem Verzeichnis in PDF zu konvertieren

Github

:octocat: https://github.com/ikota3/image_utilities

Überblick

Um bequem selbst kochen zu können, habe ich ein Tool erstellt, mit dem die in jedem Verzeichnis gespeicherten Bilder in PDF konvertiert werden können. Darüber hinaus werden Unterverzeichnisse auch rekursiv angezeigt und erstellt.

Der Vorgang wurde unter Windows 10 bestätigt.

Dinge notwendig

Wie benutzt man

$ git clone https://github.com/ikota3/image_utilities
$ cd image_utilities
$ pip install -r requirements.txt
$ python src/images_to_pdf.py convert -i "path/to/input" -o "path/to/output" -e "jpg,jpeg,png"

Implementierungsdetails

Dieses Mal dachte ich, es wäre schwierig, alles von Grund auf neu zu erstellen, um ein CLI-Tool zu erstellen. Deshalb habe ich eine Bibliothek namens fire verwendet, über die bereits gesprochen wurde. ..

In der Tat war es sehr einfach zu bedienen.

Befehle ausführen können

Erstellen Sie zunächst ein Skelett, damit Sie den Befehl drücken und den Eingabewert erhalten können. Erstellen Sie dieses Mal eine Klasse und nennen Sie sie mit Feuer. Zusätzlich zu Klassen kann fire Funktionen, Module, Objekte und viele andere Dinge aufrufen. Einzelheiten entnehmen Sie bitte dem offiziellen Dokument. https://github.com/google/python-fire/blob/master/docs/guide.md

images_to_pdf.py


import fire

class PDFConverter(object):
    """Class for convert images to pdf."""

    def __init__(
            self,
            input_dir: str = "",
            output_dir: str = "",
            extensions: Union[str, Tuple[str]] = None,
            force_write: bool = False,
            yes: bool = False
    ):
        """Initialize

        Args:
            input_dir (str): Input directory. Defaults to "".
            output_dir (str): Output directory. Defaults to "".
            extensions (Union[str, Tuple[str]]): Extensions. Defaults to None.
            force_write (bool): Flag for overwrite the converted pdf. Defaults to False.
            yes (bool): Flag for asking to execute or not. Defaults to False.
        """
        self.input_dir: str = input_dir
        self.output_dir: str = output_dir
        if not extensions:
            extensions = ('jpg', 'png')
        self.extensions: Tuple[str] = extensions
        self.force_write: bool = force_write
        self.yes: bool = yes

	def convert(self):
		print("Hello World!")


if __name__ == '__main__':
    fire.Fire(PDFConverter)

Das Skelett ist vorerst fertiggestellt. Wenn Sie in diesem Zustand einen Befehl eingeben, sollte "Hallo Welt!" Angezeigt werden.

$ python src/images_to_pdf.py convert
Hello World!

Darüber hinaus legen andere Parameter wie input_dir =" " Standardwerte fest. Wenn Sie jedoch auf der Befehlsseite keinen Wert übergeben, ohne dies festzulegen, tritt auf der Feuerseite ein Fehler auf.

Um den Wert zu übergeben, fügen Sie einfach einen Bindestrich vor dem Präfix des in __init__ festgelegten Arguments hinzu und schreiben Sie dann den Wert, den Sie übergeben möchten.

Die Methode zum Übergeben der folgenden Befehle ist dieselbe, obwohl die Schreibmethode unterschiedlich ist.

$ # self.input_dir Beispiel
$ python src/images_to_pdf.py convert -i "path/to/input"
$ python src/images_to_pdf.py convert -i="path/to/input"
$ python src/images_to_pdf.py convert --input_dir "path/to/input"
$ python src/images_to_pdf.py convert --input_dir="path/to/input"

Außerdem war ich verwirrt, als ich versuchte, die Liste als Stolperstein zu übergeben.

$ # self.Beispiele für Erweiterungen
$ python src/images_to_pdf.py convert -e jpg,png # OK
$ python src/images_to_pdf.py convert -e "jpg,png" # OK
$ python src/images_to_pdf.py convert -e "jpg, png" # OK
$ python src/images_to_pdf.py convert -e jpg, png # NG

Eingabewertprüfung

Geben Sie vor dem Ausführen der PDF-Konvertierung die Überprüfung mit "isinstance ()" ein und prüfen Sie, ob der angegebene Pfad vorhanden ist usw.

images_to_pdf.py


def _input_is_valid(self) -> bool:
    """Validator for input.

    Returns:
        bool: True if is valid, False otherwise.
    """
    is_valid = True

    # Check input_dir
    if not isinstance(self.input_dir, str) or \
            not os.path.isdir(self.input_dir):
        print('[ERROR] You must type a valid directory for input directory.')
        is_valid = False

    # Check output_dir
    if not isinstance(self.output_dir, str) or \
            not os.path.isdir(self.output_dir):
        print('[ERROR] You must type a valid directory for output directory.')
        is_valid = False

    # Check extensions
    if not isinstance(self.extensions, tuple) and \
            not isinstance(self.extensions, str):
        print('[ERROR] You must type at least one extension.')
        is_valid = False

    # Check force_write
    if not isinstance(self.force_write, bool):
        print('[ERROR] You must just type -f flag. No need to type a parameter.')
        is_valid = False

    # Check yes
    if not isinstance(self.yes, bool):
        print('[ERROR] You must just type -y flag. No need to type a parameter.')
        is_valid = False

    return is_valid

Scannen Sie das Verzeichnis, sammeln Sie Bilder und konvertieren Sie sie in PDF

Wir verwenden "os.walk ()", um das Verzeichnis vom empfangenen "input_dir" -Pfad zu scannen. https://docs.python.org/ja/3/library/os.html?highlight=os walk#os.walk

Das Verzeichnis wird wie unten gezeigt gescannt, Bilder werden gesammelt und in PDF konvertiert.

images_to_pdf.py


def convert(self):
    #Zum Präfix der Erweiterung.Hinzufügen
    extensions: Union[str | Tuple[str]] = None
    if isinstance(self.extensions, tuple):
        extensions = []
        for extension in self.extensions:
            extensions.append(f'.{extension}')
        extensions = tuple(extensions)
    elif isinstance(self.extensions, str):
        extensions = tuple([f'.{self.extensions}'])

	#Scannen Sie die Verzeichnisse und konvertieren Sie die Bilder in jedem Verzeichnis in PDF
    for current_dir, dirs, files in os.walk(self.input_dir):
        print(f'[INFO] Watching {current_dir}.')

        #Eine Liste, in der der Pfad gespeichert ist, in dem sich das Zielbild befindet
        images = []

        #Dateien ist aktuell_Liste der Dateien in dir
        #Die Sortierung ist nicht in Ordnung, wenn die Anzahl der Ziffern unterschiedlich ist(https://github.com/ikota3/image_utilities#note)
        #Deshalb habe ich eine Funktion vorbereitet, um sie wie erwartet zu machen.(Siehe unten)
        for filename in sorted(files, key=natural_keys):
            if filename.endswith(extensions):
                path = os.path.join(current_dir, filename)
                images.append(path)

		#Wenn beim Scannen kein Bild vorhanden ist
        if not images:
            print(
                f'[INFO] There are no {", ".join(self.extensions).upper()} files at {current_dir}.'
            )
            continue

        pdf_filename = os.path.join(
            self.output_dir, f'{os.path.basename(current_dir)}.pdf'
        )

		# -Wenn es einen f-Parameter gibt, überschreiben Sie ihn zwangsweise, selbst wenn eine Datei vorhanden ist
        if self.force_write:
            with open(pdf_filename, 'wb') as f:
                f.write(img2pdf.convert(images))
            print(f'[INFO] Created {pdf_filename}!')
        else:
            if os.path.exists(pdf_filename):
                print(f'[ERROR] {pdf_filename} already exist!')
                continue

            with open(pdf_filename, 'wb') as f:
                f.write(img2pdf.convert(images))
            print(f'[INFO] Created {pdf_filename}!')

Beim Sammeln der Bilder im Verzeichnis gab es Zeiten, in denen die Sortierung falsch war und die Reihenfolge nicht meinen Erwartungen entsprach. Deshalb habe ich eine Funktion vorbereitet. Außerdem habe ich es unter Bezugnahme auf den folgenden Link geschafft. https://stackoverflow.com/questions/5967500/how-to-correctly-sort-a-string-with-a-number-inside

sort_key.py


import re
from typing import Union, List


def atoi(text: str) -> Union[int, str]:
    """Convert ascii to integer.

    Args:
        text (str): string.

    Returns:
        Union[int, str]: integer if number, string otherwise.
    """
    return int(text) if text.isdigit() else text


def natural_keys(text: str) -> Union[List[int], List[str]]:
    """Key for natural sorting

    Args:
        text (str): string

    Returns:
        Union[List[int], List[str]]: A list of mixed integer and strings.
    """
    return [atoi(c) for c in re.split(r'(\d+)', text)]

das Ende

Früher habe ich CLI-Tools ohne Verwendung einer Bibliothek erstellt, aber die Implementierung war einfacher als Fire!

Möchten Sie ein CLI-Tool erstellen?

Recommended Posts

Ich habe ein CLI-Tool erstellt, um Bilder in jedem Verzeichnis in PDF zu konvertieren
Ich möchte eine in Python in PDF konvertierte Tabelle wieder in CSV konvertieren
Ich habe ein Tool erstellt, um Hy nativ zu kompilieren
Ich habe ein Netzwerk erstellt, um Schwarzweißbilder in Farbbilder umzuwandeln (pix2pix)
Ich habe ein Skript in Python erstellt, um MDD-Dateien in das Scrapbox-Format zu konvertieren
Stapelkonvertierung von PSD-Dateien im Verzeichnis in PDF
Ich habe ein Tool erstellt, um Jupyter py mit VS Code in ipynb zu konvertieren
Ich habe ein Tool erstellt, um neue Artikel zu erhalten
Ich habe ein Modul in C-Sprache erstellt, das von Python geladene Bilder filtert
Ich habe ein Skript erstellt, um ein Snippet in README.md einzufügen
Ich habe einen Code erstellt, um illustration2vec in ein Keras-Modell zu konvertieren
Ich habe ein CLI-Tool in der Sprache Go geschrieben, um Qiitas Tag-Feed in CLI anzuzeigen
Ich habe ein Tool erstellt, um eine Wortwolke aus Wikipedia zu erstellen
[Titan Craft] Ich habe ein Werkzeug gemacht, um einen Riesen nach Minecraft zu rufen
Ich habe ein Skript in Python erstellt, um eine Textdatei für JSON zu konvertieren (für das vscode-Benutzer-Snippet).
Konvertieren Sie Markdown in Python in PDF
Konvertieren Sie A4 PDF alle 2 Seiten in A3
Tool zum Konvertieren der Juniper-Konfiguration
Ich habe den Befehl gegeben, einen farbenfrohen Kalender im Terminal anzuzeigen
Ich möchte in der Einschlussnotation drucken
Ich habe ein Pay-Management-Programm in Python erstellt!
So konvertieren Sie csv in tsv in CLI
Ich habe ein Skript erstellt, um Piktogramme anzuzeigen
Ich habe ein automatisches Stempelwerkzeug für den Browser erstellt.
Ich habe ein Passwort-Tool in Python erstellt.
Ich habe ein Plugin erstellt, um mit Vim eine Markdown-Tabelle aus CSV zu generieren
Ich habe einen Code geschrieben, um die Quaternion mit Python in einen Ölerwinkel vom Typ z-y-x umzuwandeln
Ich habe ein Tool zum automatischen Durchsuchen mehrerer Websites mit Selenium (Python) erstellt.
Ich habe eine Art einfaches Bildverarbeitungswerkzeug in der Sprache Go erstellt.
Ich habe ein Tool erstellt, das die Dekomprimierung mit CLI (Python3) etwas erleichtert.
Ich habe ein Programm erstellt, um die Größe einer Datei mit Python zu überprüfen
Hinweise Ich habe nachgeschlagen, um Befehlszeilentools in Python zu erstellen
Ich habe ein Tool erstellt, um die Ausführungszeit von cron zu schätzen (+ PyPI-Debüt)
Ich habe ein nützliches Tool für Digital Ocean erstellt
Konvertieren Sie PDFs mit Python in Massenbilder
Ich möchte mit Python ein Fenster erstellen
Ich habe ein Tool erstellt, um Slack über Connpass-Ereignisse zu informieren, und es zu Terraform gemacht
Ich habe gerade ein Tool erstellt, mit dem Daten mithilfe der GUI-Operation einfach als Diagramm angezeigt werden können
Ich habe einen Appdo-Befehl erstellt, um Befehle im Kontext der App auszuführen
Ich habe ein Router-Konfigurationssammlungstool Config Collecor erstellt
Ich habe ein Tool zum Generieren von Markdown aus der exportierten Scrapbox-JSON-Datei erstellt
Ich habe ein Tool zum automatischen Sichern der Metadaten der Salesforce-Organisation erstellt
Ich habe versucht, ein scheinbar Windows-Snipper-Tool mit Python zu implementieren
So lesen Sie Dateien in verschiedenen Verzeichnissen
Ich habe ein Caesar-Kryptografieprogramm in Python erstellt.
Ich habe in Python ein Tool erstellt, das mit der rechten Maustaste auf eine Excel-Datei klickt und diese für jedes Blatt in Dateien unterteilt.
Ich kann nicht schlafen, bis ich einen Server erstellt habe !! (Einführung in den Python-Server an einem Tag)
Ich möchte Timeout einfach in Python implementieren
Lassen Sie uns Chat-Benutzerverwaltungstool gemacht
Ich möchte mit einem Knopf am Kolben übergehen
Ich habe eine Bibliothek erstellt, um japanische Sätze schön zu brechen
Ich möchte in Python schreiben! (2) Schreiben wir einen Test
Ich habe ein Reinigungstool für Google Container Registry erstellt
Ich habe versucht, einen Pseudo-Pachislot in Python zu implementieren
Ich habe ein Python-Modul erstellt, um Kommentare zu übersetzen
Konvertieren Sie das Bild in .zip mit Python in PDF
Ich möchte eine Datei mit Python zufällig testen