Ce script python permet de rajouter un filigramme dans des fichiers PDF et des images.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

main.py 9.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  1. '''
  2. Ce script Python prend en entrée un répertoire contenant des fichiers image et des PDF.
  3. 1- Pour chaque PDF trouvé, il extrait les pages sous forme d'images dans un répertoire temporaire.
  4. 2- Il parcourt toutes les images du répertoire source (défini dans le fichier config.json) et leur ajoute
  5. un filigrame en travers.
  6. 3- Chaque imags est ensuite sauvegardée dans un répertoire contenant le nom du filigramme (paramètre text
  7. dans le fichier de configuration config.json)
  8. Configuration:
  9. Toute la configuration (le filigrame et le chemin du répertoire contenant les documents) est à faire dans le
  10. fichier config.json.
  11. filigrame : le nom qui va apparaitre après la phrase : "Document exclusivement destiné à " (cette phrase n'est pas modifiable)
  12. source_directory : le chemin du répertoire contenant les documents dans lesquels il faut ajouter le filigrame.
  13. Il est conseillé de mettre un chemin absolu.
  14. '''
  15. # Press Maj+F10 to execute it or replace it with your code.
  16. # Press Double Shift to search everywhere for classes, files, tool windows, actions, and settings.
  17. import os, json, subprocess, zipfile, sys
  18. from PIL import Image, ImageDraw, ImageFont
  19. import piexif
  20. from pdf2image import convert_from_path
  21. import argparse
  22. def generate_image_with_text(text, font_size=40, line_spacing=50, transparency=0.40):
  23. text = "Document exclusivement destiné à " + text
  24. text = text + " " + text
  25. # Charger une police de caractères
  26. font = ImageFont.truetype("arial.ttf", font_size)
  27. # Obtenir les dimensions du texte
  28. nothing, nothing, text_width, text_height = font.getbbox(text)
  29. # Nombre de lignes de texte à afficher
  30. num_lines = 20
  31. # Calculer la hauteur totale de l'image en tenant compte de l'espacement entre les lignes
  32. total_height = text_height * num_lines + line_spacing * (num_lines - 1)
  33. # Créer une nouvelle image avec fond transparent
  34. text_image = Image.new("RGBA", (text_width, total_height), (0,0,0,0))
  35. # Dessiner le texte sur l'image transparente
  36. text_draw = ImageDraw.Draw(text_image)
  37. for i in range(num_lines):
  38. text_draw.text((0, (text_height + line_spacing) * i), text, fill=(150, 150, 150, int(255 * transparency)), font=font)
  39. # Appliquer une rotation de 45 degrés à l'image masque
  40. rotated_mask = text_image.rotate(45, expand=True)
  41. return rotated_mask
  42. def merge_image_with_text(source_directory, destination_directory, text):
  43. prefix = text.replace(" ", "_")
  44. # Créer le répertoire de destination s'il n'existe pas
  45. os.makedirs(destination_directory, exist_ok=True)
  46. # Liste tous les fichiers dans le répertoire source
  47. files = os.listdir(source_directory)
  48. # Générer l'image avec le texte incliné à 45 degrés
  49. text_image = generate_image_with_text(text)
  50. # Parcourir tous les fichiers du répertoire source
  51. for file in files:
  52. # Vérifier si le fichier est une image
  53. if file.lower().endswith((".jpg", ".jpeg", ".png", ".bmp")):
  54. # Chemin complet de l'image source
  55. source_image_path = os.path.join(source_directory, file)
  56. # Charger l'image source
  57. source_image = Image.open(source_image_path).convert("RGBA")
  58. # Calculer les coordonnées de collage pour centrer l'image source sur text_image
  59. paste_x = (source_image.width - text_image.width) // 2
  60. paste_y = (source_image.height - text_image.height) // 2
  61. # Créer une copie de l'image source pour éviter de la modifier
  62. merged_image = source_image.copy()
  63. # Coller l'image contenant du texte au milieu de l'image source
  64. merged_image.paste(text_image, (paste_x, paste_y), text_image)
  65. # Convertir l'image en mode RVB avant de l'enregistrer au format JPEG
  66. merged_image = merged_image.convert("RGB")
  67. # Récupérer les données EXIF de l'image source
  68. exif_data = source_image.info.get("exif")
  69. # Si des données EXIF existent, les convertir en dictionnaire
  70. if exif_data:
  71. exif_dict = piexif.load(exif_data)
  72. # Ajouter ou remplacer le tag EXIF "ImageDescription" avec le texte spécifié
  73. exif_dict["0th"][270] = "Document exclusivement destiné à " + text
  74. else:
  75. exif_dict = {}
  76. # Convertir le dictionnaire EXIF en données binaires
  77. exif_bytes = piexif.dump(exif_dict)
  78. # Enregistrer l'image fusionnée dans le répertoire de destination
  79. output_image_path = os.path.join(destination_directory, f"{prefix}{file}")
  80. merged_image.save(output_image_path, exif=exif_bytes)
  81. def extract_pdf_pages(pdf_path, text):
  82. # Création du répertoire temporaire
  83. destination_directory = os.path.join(os.path.dirname(pdf_path), "temp")
  84. # Créer le répertoire de destination s'il n'existe pas
  85. os.makedirs(destination_directory, exist_ok=True)
  86. # Convertir chaque page du PDF en image
  87. pages = convert_from_path(pdf_path)
  88. # Extraire le nom du fichier PDF sans l'extension
  89. pdf_filename = os.path.splitext(os.path.basename(pdf_path))[0]
  90. for i, page in enumerate(pages):
  91. filename = f"{pdf_filename}_page_{i+1}.jpg"
  92. output_path = os.path.join(destination_directory, filename)
  93. page.save(output_path, "JPEG")
  94. def process_pdf_files(source_directory, text):
  95. # Parcourir tous les fichiers du répertoire source
  96. for file in os.listdir(source_directory):
  97. # Vérifier si le fichier est un PDF
  98. if file.lower().endswith(".pdf"):
  99. # Chemin complet du fichier PDF
  100. pdf_path = os.path.join(source_directory, file)
  101. # Convertir le PDF en images
  102. extract_pdf_pages(pdf_path, text)
  103. def load_config():
  104. with open("./config.json") as f:
  105. config = json.load(f)
  106. return config
  107. def open_in_file_explorer(directory):
  108. # Vérifier si le répertoire existe
  109. if os.path.exists(directory):
  110. # Ouvrir l'explorateur de fichiers avec le répertoire spécifié
  111. subprocess.Popen(['explorer', directory])
  112. else:
  113. print("Le répertoire spécifié n'existe pas.")
  114. def create_original_files_directory():
  115. config = load_config()
  116. original_files_directory = config.get("source_directory")
  117. if os.path.isdir(original_files_directory):
  118. return
  119. else:
  120. temp_directory = os.path.join(os.getcwd(), f"Original_Files")
  121. os.makedirs(temp_directory)
  122. print(f"Répertoire de travail créé à l'emplacement : {temp_directory}")
  123. # Mettre à jour le chemin du répertoire dans le fichier de configuration
  124. config["source_directory"] = temp_directory
  125. with open("config.json", "w") as f:
  126. json.dump(config, f, indent=4)
  127. print(f"Sauvegarde de la configuration OK")
  128. print(f"Il ne reste plus qu'à mettre les fichiers originaux dans le répertoire ", temp_directory,"' et relancer le script.")
  129. sys.exit(1) # Arrête le script avec un code d'erreur non nul
  130. def is_key_defined_in_json(json_file, key):
  131. with open(json_file, 'r') as f:
  132. data = json.load(f)
  133. return key in data
  134. def zip_directory(directory, zip_file):
  135. with zipfile.ZipFile(zip_file, 'w', zipfile.ZIP_DEFLATED) as zipf:
  136. for root, _, files in os.walk(directory):
  137. for file in files:
  138. file_path = os.path.join(root, file)
  139. zipf.write(file_path, os.path.relpath(file_path, directory))
  140. def traitement(paramFiligramme):
  141. # Lecture de la configuration
  142. config = load_config()
  143. # Utilise la valeur du filigramme fournie ou celle par défaut de la configuration
  144. filigramme = paramFiligramme if paramFiligramme else config.get('filigrame', 'Protection par filigrame')
  145. source_directory = config["source_directory"]
  146. destination_directory = os.path.join(source_directory, filigramme.replace(" ", "_"))
  147. temp_directory = os.path.join(source_directory, "temp")
  148. # Extrait les pages des pdf
  149. try:
  150. print("Extrait les pages des pdf")
  151. process_pdf_files(source_directory, filigramme)
  152. # Rajoute le tag dans les images des pages du pdf
  153. print("Rajoute le tag dans les images des pages du pdf")
  154. merge_image_with_text(temp_directory, destination_directory, filigramme)
  155. except:
  156. print(f"Aucun fichier PDF")
  157. # Rajoute le tag sur les images du répertoire courant
  158. try:
  159. print("Rajoute le tag sur les images du répertoire courant")
  160. merge_image_with_text(source_directory, destination_directory, filigramme)
  161. # Compression du répertoire
  162. if( is_key_defined_in_json("config.json", "zipfileDirectory")):
  163. fichierZip = os.path.join(config["zipfileDirectory"], filigramme.replace(" ", "_") + ".zip")
  164. print("Compression du répertoire et sauvegarde dans ", fichierZip)
  165. zip_directory(destination_directory, fichierZip)
  166. # Ouverture du répertoire contenant toutes les images tagées
  167. # open_in_file_explorer(config["zipfileDirectory"])
  168. return {"result": "processed data with filigramme: " + filigramme}
  169. except:
  170. return {"result": "Aucune image à taguer"}
  171. def main():
  172. # Creation du répertoire sources pour mettre les documents
  173. create_original_files_directory()
  174. # Configure le parseur d'arguments
  175. parser = argparse.ArgumentParser(description='read arguments')
  176. parser.add_argument('--filigramme', type=str, help='Valeur du filigram comme "agence (juillet 2024)"')
  177. # Analyse les arguments
  178. args = parser.parse_args()
  179. traitement(args.filigramme)
  180. if __name__ == '__main__':
  181. main()