-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathgeolocexif.py
500 lines (444 loc) · 20.6 KB
/
geolocexif.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
import os
import sys
import threading
from PySide2.QtWidgets import QApplication, QWidget, QVBoxLayout, QHBoxLayout, QLabel, QFileDialog, QPushButton, QMessageBox, QStackedWidget, QTextEdit
from PySide2.QtGui import QPixmap, QIcon
from PySide2.QtCore import Qt, QObject, Signal
from PySide2.QtWebEngineWidgets import QWebEngineView
import exifread
from GPSPhoto import gpsphoto
from pyautogui import screenshot
LARGEUR_FENETRE = 1250
HAUTEUR_FENETRE = 670
LARGEUR_BOUTON = 340
HAUTEUR_BOUTON = 50
class Signaux(QObject):
afficher_donnees_exif_signal = Signal(str)
class Fenetre(QWidget):
def __init__(self):
super().__init__()
self.chemin_fichier = ""
self.setWindowTitle("BreakingTech GeoLocExif")
self.setGeometry(200, 200, LARGEUR_FENETRE, HAUTEUR_FENETRE)
self.principal_layout = QVBoxLayout()
self.principal_layout.setAlignment(Qt.AlignCenter) # Centrer les éléments horizontalement
self.stacked_widget = QStackedWidget()
self.principal_layout.addWidget(self.stacked_widget)
self.setLayout(self.principal_layout)
self.signaux = Signaux()
self.creer_vue_principale()
def creer_vue_principale(self):
widget_principal = QWidget()
layout_principal = QVBoxLayout()
layout_haut = QHBoxLayout()
# Logo geolocexif.jpg à gauche
logo_layout = QVBoxLayout()
logo_label = QLabel()
logo_pixmap = QPixmap("geolocexif.jpg")
logo_label.setPixmap(logo_pixmap)
logo_label.setAlignment(Qt.AlignCenter)
logo_layout.addWidget(logo_label)
layout_haut.addLayout(logo_layout)
# Image importée par l'utilisateur à droite du logo
self.lbl_image_selectionnee = QLabel()
layout_haut.addWidget(self.lbl_image_selectionnee)
layout_boutons = QVBoxLayout()
self.btn_parcourir = QPushButton("Choisir une photo...")
self.btn_parcourir.clicked.connect(self.parcourir)
self.btn_parcourir.setStyleSheet("""
QPushButton {
background-color: #4B4F52;
color: white;
border-radius: 5px;
}
QPushButton:hover {
background-color: #868E96;
}
""")
self.btn_parcourir.setFixedSize(LARGEUR_BOUTON, HAUTEUR_BOUTON)
layout_boutons.addWidget(self.btn_parcourir)
self.btn_geolocaliser = QPushButton("Géolocaliser")
self.btn_geolocaliser.clicked.connect(self.geolocaliser)
self.btn_geolocaliser.setFixedSize(LARGEUR_BOUTON, HAUTEUR_BOUTON)
layout_boutons.addWidget(self.btn_geolocaliser)
self.btn_geolocaliser.setEnabled(False)
if not self.chemin_fichier:
self.btn_geolocaliser.setStyleSheet("""
QPushButton {
background-color: #FFFFFF;
color: #9F9FA0;
border-radius: 5px;
}
""")
self.btn_sauvegarder = QPushButton("Sauvegarder les données")
self.btn_sauvegarder.clicked.connect(self.sauvegarder_donnees)
self.btn_sauvegarder.setFixedSize(LARGEUR_BOUTON, HAUTEUR_BOUTON)
layout_boutons.addWidget(self.btn_sauvegarder)
self.btn_sauvegarder.setEnabled(False)
if not self.chemin_fichier:
self.btn_sauvegarder.setStyleSheet("""
QPushButton {
background-color: #FFFFFF;
color: #9F9FA0;
border-radius: 5px;
}
""")
self.btn_quitter = QPushButton("Quitter")
self.btn_quitter.clicked.connect(self.quitter_application)
self.btn_quitter.setStyleSheet("""
QPushButton {
background-color: #C92A2A;
color: white;
border-radius: 5px;
}
QPushButton:hover {
background-color: #F03E3E;
}
""")
self.btn_quitter.setFixedSize(LARGEUR_BOUTON, HAUTEUR_BOUTON)
layout_boutons.addWidget(self.btn_quitter)
layout_haut.addLayout(layout_boutons)
layout_haut.addStretch() # Ajouter de l'espace à droite
layout_principal.addLayout(layout_haut)
self.txt_infos_exif_col1 = QTextEdit()
self.txt_infos_exif_col1.setStyleSheet("color: white;")
self.txt_infos_exif_col1.setReadOnly(True)
self.txt_infos_exif_col2 = QTextEdit()
self.txt_infos_exif_col2.setStyleSheet("color: white;")
self.txt_infos_exif_col2.setReadOnly(True)
self.txt_infos_exif_col3 = QTextEdit()
self.txt_infos_exif_col3.setStyleSheet("color: white;")
self.txt_infos_exif_col3.setReadOnly(True)
self.txt_infos_exif_col4 = QTextEdit()
self.txt_infos_exif_col4.setStyleSheet("color: white;")
self.txt_infos_exif_col4.setReadOnly(True)
layout_donnees_exif = QHBoxLayout()
layout_col1 = QVBoxLayout()
self.label_group1 = QLabel("Informations sur l'image", alignment=Qt.AlignCenter)
self.label_group1.setStyleSheet("color: white;")
layout_col1.addWidget(self.label_group1)
layout_col1.addWidget(self.txt_infos_exif_col1)
layout_donnees_exif.addLayout(layout_col1)
layout_col2 = QVBoxLayout()
self.label_group2 = QLabel("Réglages de l'appareil photo", alignment=Qt.AlignCenter)
self.label_group2.setStyleSheet("color: white;")
layout_col2.addWidget(self.label_group2)
layout_col2.addWidget(self.txt_infos_exif_col2)
layout_donnees_exif.addLayout(layout_col2)
layout_col3 = QVBoxLayout()
self.label_group3 = QLabel("Données temporelles", alignment=Qt.AlignCenter)
self.label_group3.setStyleSheet("color: white;")
layout_col3.addWidget(self.label_group3)
layout_col3.addWidget(self.txt_infos_exif_col3)
layout_donnees_exif.addLayout(layout_col3)
layout_col4 = QVBoxLayout()
self.label_group4 = QLabel("Géolocalisation", alignment=Qt.AlignCenter)
self.label_group4.setStyleSheet("color: white;")
layout_col4.addWidget(self.label_group4)
layout_col4.addWidget(self.txt_infos_exif_col4)
layout_donnees_exif.addLayout(layout_col4)
layout_principal.addLayout(layout_donnees_exif)
widget_principal.setLayout(layout_principal)
self.stacked_widget.addWidget(widget_principal)
self.setStyleSheet("background-color: black;")
def geolocaliser(self):
if self.chemin_fichier == "":
self.afficher_message_erreur("Veuillez d'abord parcourir une photo")
return
try:
coords = gpsphoto.getGPSData(self.chemin_fichier)
if not coords:
self.afficher_message_erreur("Les coordonnées GPS ne sont pas disponibles pour cette image")
return
latitude = coords['Latitude']
longitude = coords['Longitude']
# Afficher les coordonnées sur la carte Google Maps
widget_carte = QWidget()
layout = QVBoxLayout()
self.web_view = QWebEngineView()
self.web_view.load(f"http://maps.google.com/?q={latitude},{longitude}")
layout.addWidget(self.web_view)
layout_boutons = QHBoxLayout()
self.btn_retour = QPushButton("Retourner au menu")
self.btn_retour.clicked.connect(self.afficher_vue_principale)
self.btn_retour.setStyleSheet("""
QPushButton {
background-color: #4B4F52;
color: white;
border-radius: 5px;
}
QPushButton:hover {
background-color: #868E96;
}
""")
self.btn_retour.setFixedSize(LARGEUR_BOUTON, HAUTEUR_BOUTON)
layout_boutons.addWidget(self.btn_retour)
self.btn_screenshot = QPushButton("Screenshot GoogleMap")
self.btn_screenshot.clicked.connect(self.screenshot_googlemap)
self.btn_screenshot.setStyleSheet("""
QPushButton {
background-color: #099268;
color: white;
border-radius: 5px;
}
QPushButton:hover {
background-color: #20C997;
}
""")
self.btn_screenshot.setFixedSize(LARGEUR_BOUTON, HAUTEUR_BOUTON)
layout_boutons.addWidget(self.btn_screenshot)
self.btn_quitter_carte = QPushButton("Quitter")
self.btn_quitter_carte.clicked.connect(self.quitter_application)
self.btn_quitter_carte.setStyleSheet("""
QPushButton {
background-color: #C92A2A;
color: white;
border-radius: 5px;
}
QPushButton:hover {
background-color: #F03E3E;
}
""")
self.btn_quitter_carte.setFixedSize(LARGEUR_BOUTON, HAUTEUR_BOUTON)
layout_boutons.addWidget(self.btn_quitter_carte)
layout.addLayout(layout_boutons)
widget_carte.setLayout(layout)
self.stacked_widget.addWidget(widget_carte)
self.stacked_widget.setCurrentWidget(widget_carte)
except Exception as e:
self.afficher_message_erreur(str(e))
def screenshot_googlemap(self):
save_path, _ = QFileDialog.getSaveFileName(self, "Enregistrer le screenshot", "", "JPEG Files (*.jpg)")
if save_path:
self.web_view.grab().save(save_path, "jpg")
def afficher_vue_principale(self):
self.stacked_widget.setCurrentIndex(0)
def afficher_message_erreur(self, message):
msg = QMessageBox()
msg.setIcon(QMessageBox.Critical)
msg.setText("Erreur")
msg.setInformativeText(message)
msg.setWindowTitle("Erreur")
msg.exec_()
def quitter_application(self):
sys.exit()
def sauvegarder_donnees(self):
if self.chemin_fichier == "":
self.afficher_message_erreur("Veuillez d'abord parcourir une photo")
return
nom_fichier = os.path.basename(self.chemin_fichier)
nom_fichier_sans_extension = os.path.splitext(nom_fichier)[0]
nom_fichier_donnees = f"{nom_fichier_sans_extension}_donnees_exif.txt"
save_path, _ = QFileDialog.getSaveFileName(self, "Enregistrer les données Exif", nom_fichier_donnees, "Text Files (*.txt)")
if save_path:
chemin_sauvegarde = save_path
try:
with open(chemin_sauvegarde, "w") as f:
f.write(self.txt_infos_exif_col1.toPlainText() + "\n")
f.write(self.txt_infos_exif_col2.toPlainText() + "\n")
f.write(self.txt_infos_exif_col3.toPlainText() + "\n")
f.write(self.txt_infos_exif_col4.toPlainText() + "\n")
self.afficher_message_information("Données Exif sauvegardées avec succès")
except Exception as e:
self.afficher_message_erreur(str(e))
def parcourir(self):
chemin_fichier, _ = QFileDialog.getOpenFileName(self, "Choisir une photo", "", "Images (*.jpg *.jpeg *.png *.gif)")
if chemin_fichier:
self.chemin_fichier = chemin_fichier
self.afficher_image()
self.effacer_donnees_exif()
threading.Thread(target=self.afficher_donnees_exif).start()
self.btn_geolocaliser.setEnabled(True)
self.btn_geolocaliser.setStyleSheet("""
QPushButton {
background-color: #1971C2;
color: white;
border-radius: 5px;
}
QPushButton:hover {
background-color: #228BE6;
}
""")
self.btn_sauvegarder.setEnabled(True)
self.btn_sauvegarder.setStyleSheet("""
QPushButton {
background-color: #099268;
color: white;
border-radius: 5px;
}
QPushButton:hover {
background-color: #20C997;
}
""")
def afficher_image(self):
pixmap = QPixmap(self.chemin_fichier)
if pixmap.width() > 200:
pixmap = pixmap.scaledToWidth(200, Qt.SmoothTransformation)
self.lbl_image_selectionnee.setPixmap(pixmap)
self.lbl_image_selectionnee.setAlignment(Qt.AlignCenter)
def afficher_message_information(self, message):
msg = QMessageBox()
msg.setIcon(QMessageBox.Information)
msg.setText("Information")
msg.setInformativeText(message)
msg.setWindowTitle("Information")
msg.exec_()
def effacer_donnees_exif(self):
self.txt_infos_exif_col1.clear()
self.txt_infos_exif_col2.clear()
self.txt_infos_exif_col3.clear()
self.txt_infos_exif_col4.clear()
def afficher_donnees_exif(self):
donnees_exif = self.recuperer_donnees_exif(self.chemin_fichier)
groupes_exif = {
"Informations sur l'image": [],
"Réglages de l'appareil photo": [],
"Données temporelles": [],
"Géolocalisation": []
}
for tag, valeur in donnees_exif.items():
if "MakerNote" not in tag:
if "Image" in tag:
groupes_exif["Informations sur l'image"].append(f"{self.traduire_propriete(tag)}: <font color='yellow'>{valeur}</font>\n")
elif "GPS" in tag:
groupes_exif["Géolocalisation"].append(f"{self.traduire_propriete(tag)}: <font color='yellow'>{valeur}</font>\n")
elif "EXIF" in tag:
groupes_exif["Réglages de l'appareil photo"].append(f"{self.traduire_propriete(tag)}: <font color='yellow'>{valeur}</font>\n")
else:
groupes_exif["Données temporelles"].append(f"{self.traduire_propriete(tag)}: <font color='yellow'>{valeur}</font>\n")
col_index = 0
for titre_groupe, donnees_groupe in groupes_exif.items():
if donnees_groupe:
for donnee in donnees_groupe:
if col_index == 0:
self.txt_infos_exif_col1.append(donnee)
elif col_index == 1:
self.txt_infos_exif_col2.append(donnee)
elif col_index == 2:
self.txt_infos_exif_col3.append(donnee)
else:
self.txt_infos_exif_col4.append(donnee)
col_index = (col_index + 1) % 4
def traduire_propriete(self, tag):
traductions = {
"Image Make": "Fabricant de l'image",
"Image Model": "Modèle de l'image",
"Image Orientation": "Orientation de l'image",
"Image XResolution": "Résolution X de l'image",
"Image YResolution": "Résolution Y de l'image",
"Image ResolutionUnit": "Unité de résolution de l'image",
"Image Software": "Logiciel de l'image",
"Image DateTime": "Date/Heure de l'image",
"Image HostComputer": "Ordinateur Hôte de l'image",
"Image TileWidth": "Largeur de la vignette de l'image",
"Image TileLength": "Longueur de la vignette de l'image",
"Image YCbCrPositioning": "Positionnement YCbCr de l'image",
"Image ExifOffset": "Décalage Exif de l'image",
"Image GPSInfo": "Infos GPS de l'image",
"EXIF ExifImageWidth": "Largeur de l'image",
"EXIF ExifImageLength": "Longueur de l'image",
"Appareil Photo ExposureTime": "Temps d'exposition",
"Appareil Photo FNumber": "Numéro F",
"Appareil Photo ExposureProgram": "Programme d'exposition",
"Appareil Photo ISOSpeedRatings": "Sensibilité ISO",
"Appareil Photo ExifVersion": "Version Exif",
"Appareil Photo DateTimeOriginal": "Date/Heure d'origine",
"Appareil Photo DateTimeDigitized": "Date/Heure de numérisation",
"Appareil Photo OffsetTime": "Décalage horaire",
"Appareil Photo OffsetTimeOriginal": "Décalage horaire d'origine",
"Appareil Photo OffsetTimeDigitized": "Décalage horaire de numérisation",
"Appareil Photo ComponentsConfiguration": "Configuration des composants",
"Appareil Photo ShutterSpeedValue": "Vitesse d'obturation",
"Appareil Photo ApertureValue": "Valeur d'ouverture",
"Appareil Photo BrightnessValue": "Valeur de luminosité",
"Appareil Photo ExposureBiasValue": "Compensation d'exposition",
"Appareil Photo MeteringMode": "Mode de mesure",
"Appareil Photo Flash": "Flash",
"Appareil Photo FocalLength": "Longueur focale",
"Appareil Photo SubjectArea": "Zone de sujet",
"Appareil Photo SubSecTimeOriginal": "Temps SubSec d'origine",
"Appareil Photo SubSecTimeDigitized": "Temps SubSec de numérisation",
"Appareil Photo FlashPixVersion": "Version FlashPix",
"Appareil Photo ColorSpace": "Espace colorimétrique",
"Appareil Photo SensingMethod": "Méthode de détection",
"Appareil Photo SceneType": "Type de scène",
"Appareil Photo ExposureMode": "Mode d'exposition",
"Appareil Photo WhiteBalance": "Balance des blancs",
"Appareil Photo FocalLengthIn35mmFilm": "Longueur focale en 35mm",
"Appareil Photo SceneCaptureType": "Type de capture de scène",
"Appareil Photo LensSpecification": "Spécification de l'objectif",
"Appareil Photo LensMake": "Fabricant de l'objectif",
"Appareil Photo LensModel": "Modèle de l'objectif",
"Appareil Photo Tag 0xA460": "Tag 0xA460",
"GPS GPSLatitudeRef": "Référence de latitude",
"GPS GPSLatitude": "Latitude",
"GPS GPSLongitudeRef": "Référence de longitude",
"GPS GPSLongitude": "Longitude GPS",
"GPS GPSAltitudeRef": "Référence d'altitude",
"GPS GPSAltitude": "Altitude GPS",
"GPS GPSSpeedRef": "Référence de vitesse",
"GPS GPSSpeed": "Vitesse GPS",
"GPS GPSImgDirectionRef": "Référence de direction d'image",
"GPS GPSImgDirection": "Direction d'image",
"GPS GPSDestBearingRef": "Référence de cap de destination",
"GPS GPSDestBearing": "Cap de destination",
"GPS Tag 0x001F": "Tag 0x001F",
"GPS GPSDate": "Date GPS",
"GPS GPSTimeStamp":"Horodatage",
"EXIF ExposureTime": "Temps d'exposition",
"EXIF FNumber": "Numéro F",
"EXIF ExposureProgram": "Programme d'exposition",
"EXIF ISOSpeedRatings": "Valeurs de sensibilité ISO",
"EXIF ExifVersion": "Version Exif",
"EXIF DateTimeOriginal": "Date/Heure d'origine",
"EXIF DateTimeDigitized": "Date/Heure de numérisation",
"EXIF OffsetTime": "Heure de décalage",
"EXIF OffsetTimeOriginal": "Heure de décalage d'origine",
"EXIF OffsetTimeDigitized": "Heure de décalage de numérisation",
"EXIF ComponentsConfiguration": "Configuration de composants",
"EXIF ShutterSpeedValue": "Valeur de vitesse d'obturation",
"EXIF ApertureValue": "Valeur d'ouverture",
"EXIF BrightnessValue": "Valeur de luminosité",
"EXIF ExposureBiasValue": "Valeur de correction d'exposition",
"EXIF MeteringMode": "Mode de mesure",
"EXIF Flash": "Flash",
"EXIF FocalLength": "Longueur focale",
"EXIF SubjectArea": "Zone sujet",
"EXIF SubSecTimeOriginal": "Sous-seconde d'origine",
"EXIF SubSecTimeDigitized": "Sous-seconde de numérisation",
"EXIF FlashPixVersion": "Version FlashPix",
"EXIF ColorSpace": "Espace couleur",
"EXIF SensingMethod": "Méthode de détection",
"EXIF SceneType": "Type de scène",
"EXIF ExposureMode": "Mode d'exposition",
"EXIF WhiteBalance": "Balance des blancs",
"EXIF FocalLengthIn35mmFilm": "Longueur focale en film 35 mm",
"EXIF SceneCaptureType": "Type de capture de scène",
"EXIF LensSpecification": "Spécification de l'objectif",
"EXIF LensMake": "Fabricant de l'objectif",
"EXIF LensModel": "Modèle de l'objectif",
"EXIF Tag 0xA460": "Tag 0xA460",
"EXIF UserComment": "Commentaire de l'utilisateur",
"Image ImageWidth": "Largeur de l'image",
"Image ImageLength": "Longueur de l'image",
"Image SamplesPerPixel": "Échantillons d'images par pixel",
"Thumbnail XResolution":"Vignette XResolution",
"Thumbnail JPEGInterchangeFormatLength":"Longueur du format d'échange JPEG des vignettes",
"Image BitsPerSample":"Bits d'image par échantillon",
"Thumbnail YResolution":"Vignette YResolution",
"JPEGThumbnail":"Miniature JPEG",
"Image PhotometricInterpretation":"Image Interprétation photométrique",
"Thumbnail ResolutionUnit":"Unité de résolution des vignettes"
}
return traductions.get(tag, tag)
def recuperer_donnees_exif(self, chemin_fichier):
with open(chemin_fichier, 'rb') as f:
tags = exifread.process_file(f)
return {tag: str(value) for tag, value in tags.items()}
def main():
app = QApplication([])
fenetre = Fenetre()
fenetre.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()