Github
:octocat: https://github.com/ikota3/image_utilities
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.
fire
img2pdf
$ 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"
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.
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
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
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)]
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