Github
:octocat: https://github.com/ikota3/image_utilities
Afin de cuisiner confortablement par moi-même, j'ai créé un outil pour convertir les images stockées dans chaque répertoire en PDF. En outre, les sous-répertoires sont également affichés et créés de manière récursive.
L'opération a été confirmée sous Windows 10.
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"
Cette fois, j'ai pensé qu'il serait difficile de tout faire à partir de zéro pour créer un outil CLI, j'ai donc utilisé une bibliothèque appelée fire dont on parlait auparavant. ..
En fait, c'était très facile à utiliser.
Tout d'abord, créez un squelette afin de pouvoir appuyer sur la commande et recevoir la valeur d'entrée. Cette fois, créez une classe et appelez-la avec le feu. En plus des classes, fire peut appeler des fonctions, des modules, des objets et bien d'autres choses. Veuillez consulter le document officiel pour plus de détails. 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)
Pour le moment, le squelette est terminé. Si vous tapez une commande dans cet état, vous devriez voir "Hello World!".
$ python src/images_to_pdf.py convert
Hello World!
De plus, d'autres paramètres tels que ʻinput_dir = "" `ont des valeurs par défaut, mais si vous ne passez pas les valeurs du côté commande sans les définir, une erreur du côté feu se produira.
Pour transmettre la valeur, ajoutez simplement un trait d'union avant le préfixe de l'argument défini dans __init__
, puis écrivez la valeur que vous souhaitez transmettre.
La méthode de transmission des commandes suivantes est la même, bien que la méthode d'écriture soit différente.
$ # self.input_exemple de dir
$ 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"
De plus, j'étais confus lorsque j'ai essayé de faire passer la liste comme une pierre d'achoppement.
$ # self.Exemples d'extensions
$ 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
Avant d'effectuer le processus de conversion PDF, tapez check by ʻis instance () `et vérifiez si le chemin spécifié existe, etc. sont effectués.
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
Nous utilisons quelque chose appelé ʻos.walk () pour scanner le répertoire à partir du chemin ʻinput_dir
reçu.
https://docs.python.org/ja/3/library/os.html?highlight=os walk#os.walk
Le répertoire est numérisé comme indiqué ci-dessous, les images sont collectées et converties au format PDF.
images_to_pdf.py
def convert(self):
#Au préfixe de l'extension.Ajouter
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}'])
#Scannez les répertoires et convertissez les images de chaque répertoire en PDF
for current_dir, dirs, files in os.walk(self.input_dir):
print(f'[INFO] Watching {current_dir}.')
#Une liste qui stocke le chemin où se trouve l'image cible
images = []
#les fichiers sont à jour_Liste des fichiers dans le répertoire
#Le tri sera dans le désordre si le nombre de chiffres est différent(https://github.com/ikota3/image_utilities#note)
#Par conséquent, j'ai préparé une fonction pour la rendre comme prévu.(Voir ci-dessous)
for filename in sorted(files, key=natural_keys):
if filename.endswith(extensions):
path = os.path.join(current_dir, filename)
images.append(path)
#Lorsqu'il n'y a pas d'image à la suite de la numérisation
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'
)
# -S'il y a un paramètre f, écraser de force même s'il y a un fichier
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}!')
Lors de la collecte des images dans le répertoire, il y avait des moments où le tri était incorrect et l'ordre n'était pas ce à quoi je m'attendais, alors j'ai préparé une fonction. Aussi, je l'ai fait en me référant au lien suivant. 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)]
J'avais l'habitude de créer des outils CLI sans utiliser de bibliothèque, mais c'était plus facile à implémenter que le feu!
Souhaitez-vous créer un outil CLI?
Recommended Posts