geopic-tag-reader 1.1.1__py3-none-any.whl → 1.1.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- geopic_tag_reader/__init__.py +1 -1
- geopic_tag_reader/camera.py +14 -3
- geopic_tag_reader/i18n.py +8 -0
- geopic_tag_reader/reader.py +46 -25
- geopic_tag_reader/translations/fr/LC_MESSAGES/geopic_tag_reader.po +114 -0
- geopic_tag_reader/translations/geopic_tag_reader.pot +111 -0
- geopic_tag_reader/writer.py +5 -2
- {geopic_tag_reader-1.1.1.dist-info → geopic_tag_reader-1.1.2.dist-info}/METADATA +12 -39
- geopic_tag_reader-1.1.2.dist-info/RECORD +15 -0
- geopic_tag_reader-1.1.1.dist-info/RECORD +0 -12
- {geopic_tag_reader-1.1.1.dist-info → geopic_tag_reader-1.1.2.dist-info}/LICENSE +0 -0
- {geopic_tag_reader-1.1.1.dist-info → geopic_tag_reader-1.1.2.dist-info}/WHEEL +0 -0
- {geopic_tag_reader-1.1.1.dist-info → geopic_tag_reader-1.1.2.dist-info}/entry_points.txt +0 -0
geopic_tag_reader/__init__.py
CHANGED
geopic_tag_reader/camera.py
CHANGED
|
@@ -39,11 +39,22 @@ def is_360(make: Optional[str] = None, model: Optional[str] = None, width: Optio
|
|
|
39
39
|
True
|
|
40
40
|
>>> is_360("GoPro", "Max 360", "1024", "768")
|
|
41
41
|
False
|
|
42
|
+
>>> is_360("RICOH", "THETA S", "5376", "2688")
|
|
43
|
+
True
|
|
42
44
|
"""
|
|
43
45
|
|
|
46
|
+
# Check make and model are defined
|
|
44
47
|
if not make or not model:
|
|
45
48
|
return False
|
|
46
49
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
+
# Check width and height are equirectangular
|
|
51
|
+
if not ((width is None or height is None) or int(width) == 2 * int(height)):
|
|
52
|
+
return False
|
|
53
|
+
|
|
54
|
+
# Find make
|
|
55
|
+
matchMake = next((m for m in EQUIRECTANGULAR_MODELS.keys() if make.lower() == m.lower()), None)
|
|
56
|
+
if matchMake is None:
|
|
57
|
+
return False
|
|
58
|
+
|
|
59
|
+
# Find model
|
|
60
|
+
return any(model.lower().startswith(m.lower()) for m in EQUIRECTANGULAR_MODELS[matchMake])
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import gettext
|
|
2
|
+
import os
|
|
3
|
+
|
|
4
|
+
lang_code = globals().get("LANG") or os.getenv("LANG") or "en"
|
|
5
|
+
localedir = os.path.join(os.path.abspath(os.path.dirname(__file__)), "translations")
|
|
6
|
+
lang = gettext.translation("geopic_tag_reader", localedir, languages=[lang_code], fallback=True)
|
|
7
|
+
lang.install()
|
|
8
|
+
_ = lang.gettext
|
geopic_tag_reader/reader.py
CHANGED
|
@@ -9,6 +9,7 @@ from fractions import Fraction
|
|
|
9
9
|
from geopic_tag_reader import camera
|
|
10
10
|
import timezonefinder # type: ignore
|
|
11
11
|
import pytz
|
|
12
|
+
from geopic_tag_reader.i18n import _
|
|
12
13
|
|
|
13
14
|
# This is a fix for invalid MakerNotes leading to picture not read at all
|
|
14
15
|
# https://github.com/LeoHsiao1/pyexiv2/issues/58
|
|
@@ -173,9 +174,9 @@ def readPictureMetadata(picture: bytes) -> GeoPicTags:
|
|
|
173
174
|
|
|
174
175
|
# Check coordinates validity
|
|
175
176
|
if lat is not None and (lat < -90 or lat > 90):
|
|
176
|
-
raise InvalidExifException("Read latitude is out of WGS84 bounds (should be in [-90, 90])")
|
|
177
|
+
raise InvalidExifException(_("Read latitude is out of WGS84 bounds (should be in [-90, 90])"))
|
|
177
178
|
if lon is not None and (lon < -180 or lon > 180):
|
|
178
|
-
raise InvalidExifException("Read longitude is out of WGS84 bounds (should be in [-180, 180])")
|
|
179
|
+
raise InvalidExifException(_("Read longitude is out of WGS84 bounds (should be in [-180, 180])"))
|
|
179
180
|
|
|
180
181
|
# Parse date/time
|
|
181
182
|
d, llw = decodeGPSDateTime(data, "Exif.GPSInfo", lat, lon)
|
|
@@ -217,7 +218,7 @@ def readPictureMetadata(picture: bytes) -> GeoPicTags:
|
|
|
217
218
|
)
|
|
218
219
|
|
|
219
220
|
except Exception as e:
|
|
220
|
-
warnings.append("Skipping Mapillary date/time as it was not recognized
|
|
221
|
+
warnings.append(_("Skipping Mapillary date/time as it was not recognized: {v}").format(v=data["MAPGpsTime"]))
|
|
221
222
|
|
|
222
223
|
# Heading/Yaw
|
|
223
224
|
heading = None
|
|
@@ -230,7 +231,7 @@ def readPictureMetadata(picture: bytes) -> GeoPicTags:
|
|
|
230
231
|
heading = gpanoHeading
|
|
231
232
|
else:
|
|
232
233
|
if gpsDir != gpanoHeading:
|
|
233
|
-
warnings.append("Contradicting heading values found, GPSImgDirection value is used")
|
|
234
|
+
warnings.append(_("Contradicting heading values found, GPSImgDirection value is used"))
|
|
234
235
|
heading = gpsDir
|
|
235
236
|
|
|
236
237
|
elif isExifTagUsable(data, "Xmp.GPano.PoseHeadingDegrees", float):
|
|
@@ -341,18 +342,25 @@ def readPictureMetadata(picture: bytes) -> GeoPicTags:
|
|
|
341
342
|
errors = []
|
|
342
343
|
missing_fields = set()
|
|
343
344
|
if not lat or not lon:
|
|
344
|
-
errors.append("No GPS coordinates or broken coordinates in picture EXIF tags")
|
|
345
|
+
errors.append(_("No GPS coordinates or broken coordinates in picture EXIF tags"))
|
|
345
346
|
if not lat:
|
|
346
347
|
missing_fields.add("lat")
|
|
347
348
|
if not lon:
|
|
348
349
|
missing_fields.add("lon")
|
|
349
350
|
if d is None:
|
|
350
|
-
errors.append("No valid date in picture EXIF tags")
|
|
351
|
+
errors.append(_("No valid date in picture EXIF tags"))
|
|
351
352
|
missing_fields.add("datetime")
|
|
352
353
|
|
|
353
354
|
if errors:
|
|
355
|
+
if len(errors) > 1:
|
|
356
|
+
listOfErrors = _("The picture is missing mandatory metadata:")
|
|
357
|
+
errorSep = "\n\t- "
|
|
358
|
+
listOfErrors += errorSep + errorSep.join(errors)
|
|
359
|
+
else:
|
|
360
|
+
listOfErrors = errors[0]
|
|
361
|
+
|
|
354
362
|
raise PartialExifException(
|
|
355
|
-
|
|
363
|
+
listOfErrors,
|
|
356
364
|
missing_fields,
|
|
357
365
|
PartialGeoPicTags(
|
|
358
366
|
lat,
|
|
@@ -419,7 +427,7 @@ def decodeManyFractions(value: str) -> List[Fraction]:
|
|
|
419
427
|
return vals
|
|
420
428
|
|
|
421
429
|
except:
|
|
422
|
-
raise ValueError("Not a valid list of fractions")
|
|
430
|
+
raise ValueError(_("Not a valid list of fractions"))
|
|
423
431
|
|
|
424
432
|
|
|
425
433
|
def decodeLatLon(data: dict, group: str) -> Tuple[Optional[float], Optional[float], List[str]]:
|
|
@@ -432,7 +440,7 @@ def decodeLatLon(data: dict, group: str) -> Tuple[Optional[float], Optional[floa
|
|
|
432
440
|
latRaw = decodeManyFractions(data[f"{group}.GPSLatitude"])
|
|
433
441
|
if len(latRaw) == 3:
|
|
434
442
|
if not isExifTagUsable(data, f"{group}.GPSLatitudeRef"):
|
|
435
|
-
warnings.append("GPSLatitudeRef not found, assuming GPSLatitudeRef is North")
|
|
443
|
+
warnings.append(_("GPSLatitudeRef not found, assuming GPSLatitudeRef is North"))
|
|
436
444
|
latRef = 1
|
|
437
445
|
else:
|
|
438
446
|
latRef = -1 if data[f"{group}.GPSLatitudeRef"].startswith("S") else 1
|
|
@@ -440,10 +448,10 @@ def decodeLatLon(data: dict, group: str) -> Tuple[Optional[float], Optional[floa
|
|
|
440
448
|
|
|
441
449
|
lonRaw = decodeManyFractions(data[f"{group}.GPSLongitude"])
|
|
442
450
|
if len(lonRaw) != 3:
|
|
443
|
-
raise InvalidExifException("Broken GPS coordinates in picture EXIF tags")
|
|
451
|
+
raise InvalidExifException(_("Broken GPS coordinates in picture EXIF tags"))
|
|
444
452
|
|
|
445
453
|
if not isExifTagUsable(data, f"{group}.GPSLongitudeRef"):
|
|
446
|
-
warnings.append("GPSLongitudeRef not found, assuming GPSLongitudeRef is East")
|
|
454
|
+
warnings.append(_("GPSLongitudeRef not found, assuming GPSLongitudeRef is East"))
|
|
447
455
|
lonRef = 1
|
|
448
456
|
else:
|
|
449
457
|
lonRef = -1 if data[f"{group}.GPSLongitudeRef"].startswith("W") else 1
|
|
@@ -461,13 +469,13 @@ def decodeLatLon(data: dict, group: str) -> Tuple[Optional[float], Optional[floa
|
|
|
461
469
|
if rawLat and rawLon:
|
|
462
470
|
latRef = 1
|
|
463
471
|
if not isExifTagUsable(data, f"{group}.GPSLatitudeRef"):
|
|
464
|
-
warnings.append("GPSLatitudeRef not found, assuming GPSLatitudeRef is North")
|
|
472
|
+
warnings.append(_("GPSLatitudeRef not found, assuming GPSLatitudeRef is North"))
|
|
465
473
|
else:
|
|
466
474
|
latRef = -1 if data[f"{group}.GPSLatitudeRef"].startswith("S") else 1
|
|
467
475
|
|
|
468
476
|
lonRef = 1
|
|
469
477
|
if not isExifTagUsable(data, f"{group}.GPSLongitudeRef"):
|
|
470
|
-
warnings.append("GPSLongitudeRef not found, assuming GPSLongitudeRef is East")
|
|
478
|
+
warnings.append(_("GPSLongitudeRef not found, assuming GPSLongitudeRef is East"))
|
|
471
479
|
else:
|
|
472
480
|
lonRef = -1 if data[f"{group}.GPSLongitudeRef"].startswith("W") else 1
|
|
473
481
|
|
|
@@ -518,15 +526,19 @@ def decodeDateTimeOriginal(
|
|
|
518
526
|
# Otherwise, default to UTC + warning
|
|
519
527
|
else:
|
|
520
528
|
d = d.replace(tzinfo=datetime.timezone.utc)
|
|
521
|
-
warnings.append("Precise timezone information not found, fallback to UTC")
|
|
529
|
+
warnings.append(_("Precise timezone information not found, fallback to UTC"))
|
|
522
530
|
|
|
523
531
|
# Otherwise, default to UTC + warning
|
|
524
532
|
else:
|
|
525
533
|
d = d.replace(tzinfo=datetime.timezone.utc)
|
|
526
|
-
warnings.append("Precise timezone information not found (and no GPS coordinates to help), fallback to UTC")
|
|
534
|
+
warnings.append(_("Precise timezone information not found (and no GPS coordinates to help), fallback to UTC"))
|
|
527
535
|
|
|
528
536
|
except ValueError as e:
|
|
529
|
-
warnings.append(
|
|
537
|
+
warnings.append(
|
|
538
|
+
_("Skipping original date/time (from {datefield}) as it was not recognized: {v}").format(
|
|
539
|
+
datefield=datetimeField, v=data[datetimeField]
|
|
540
|
+
)
|
|
541
|
+
)
|
|
530
542
|
|
|
531
543
|
return (d, warnings)
|
|
532
544
|
|
|
@@ -555,16 +567,19 @@ def decodeGPSDateTime(
|
|
|
555
567
|
elif isExifTagUsable(data, f"{group}.GPSDateTime", List[Fraction]):
|
|
556
568
|
timeRaw = decodeManyFractions(data[f"{group}.GPSDateTime"])
|
|
557
569
|
else:
|
|
558
|
-
|
|
570
|
+
timeRaw = None
|
|
571
|
+
warnings.append(
|
|
572
|
+
_("GPSTimeStamp and GPSDateTime don't contain supported time format (in {group} group)").format(group=group)
|
|
573
|
+
)
|
|
559
574
|
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
575
|
+
if timeRaw:
|
|
576
|
+
seconds, microseconds, msw = decodeSecondsAndMicroSeconds(
|
|
577
|
+
str(float(timeRaw[2])),
|
|
578
|
+
data["Exif.Photo.SubSecTimeOriginal"] if isExifTagUsable(data, "Exif.Photo.SubSecTimeOriginal", float) else "0",
|
|
579
|
+
)
|
|
564
580
|
|
|
565
|
-
|
|
581
|
+
warnings += msw
|
|
566
582
|
|
|
567
|
-
if timeRaw:
|
|
568
583
|
d = datetime.datetime.combine(
|
|
569
584
|
datetime.date.fromisoformat(dateRaw),
|
|
570
585
|
datetime.time(
|
|
@@ -583,7 +598,11 @@ def decodeGPSDateTime(
|
|
|
583
598
|
d = d.astimezone(pytz.timezone(tz_name))
|
|
584
599
|
|
|
585
600
|
except ValueError as e:
|
|
586
|
-
warnings.append(
|
|
601
|
+
warnings.append(
|
|
602
|
+
_("Skipping GPS date/time ({group} group) as it was not recognized: {v}").format(
|
|
603
|
+
group=group, v=data[f"{group}.GPSDateStamp"]
|
|
604
|
+
)
|
|
605
|
+
)
|
|
587
606
|
|
|
588
607
|
return (d, warnings)
|
|
589
608
|
|
|
@@ -605,7 +624,9 @@ def decodeSecondsAndMicroSeconds(secondsRaw: str, microsecondsRaw: str) -> Tuple
|
|
|
605
624
|
# Check if microseconds from decimal seconds is not mismatching microseconds from SubSecTime field
|
|
606
625
|
if microseconds != microsecondsFromSeconds and microseconds > 0 and microsecondsFromSeconds > 0:
|
|
607
626
|
warnings.append(
|
|
608
|
-
|
|
627
|
+
_(
|
|
628
|
+
"Microseconds read from decimal seconds value ({microsecondsFromSeconds}) is not matching value from EXIF field ({microseconds}). Max value will be kept."
|
|
629
|
+
).format(microsecondsFromSeconds=microsecondsFromSeconds, microseconds=microseconds)
|
|
609
630
|
)
|
|
610
631
|
microseconds = max(microseconds, microsecondsFromSeconds)
|
|
611
632
|
else:
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
# French translations for PACKAGE package.
|
|
2
|
+
# Copyright (C) 2024 THE PACKAGE'S COPYRIGHT HOLDER
|
|
3
|
+
# This file is distributed under the same license as the PACKAGE package.
|
|
4
|
+
# Adrien <panieravide@riseup.net>, 2024.
|
|
5
|
+
#
|
|
6
|
+
msgid ""
|
|
7
|
+
msgstr ""
|
|
8
|
+
"Project-Id-Version: PACKAGE VERSION\n"
|
|
9
|
+
"Report-Msgid-Bugs-To: \n"
|
|
10
|
+
"POT-Creation-Date: 2024-06-18 09:12+0200\n"
|
|
11
|
+
"PO-Revision-Date: 2024-06-18 09:09+0000\n"
|
|
12
|
+
"Last-Translator: PanierAvide <adrien@pavie.info>\n"
|
|
13
|
+
"Language-Team: French <http://weblate.panoramax.xyz/projects/panoramax/"
|
|
14
|
+
"tag-reader/fr/>\n"
|
|
15
|
+
"Language: fr\n"
|
|
16
|
+
"MIME-Version: 1.0\n"
|
|
17
|
+
"Content-Type: text/plain; charset=UTF-8\n"
|
|
18
|
+
"Content-Transfer-Encoding: 8bit\n"
|
|
19
|
+
"Plural-Forms: nplurals=2; plural=n > 1;\n"
|
|
20
|
+
"X-Generator: Weblate 5.4.3\n"
|
|
21
|
+
|
|
22
|
+
#: geopic_tag_reader/reader.py:177
|
|
23
|
+
msgid "Read latitude is out of WGS84 bounds (should be in [-90, 90])"
|
|
24
|
+
msgstr ""
|
|
25
|
+
"La latitude est hors des limites du WGS84 (devrait être entre [-90, 90])"
|
|
26
|
+
|
|
27
|
+
#: geopic_tag_reader/reader.py:179
|
|
28
|
+
msgid "Read longitude is out of WGS84 bounds (should be in [-180, 180])"
|
|
29
|
+
msgstr ""
|
|
30
|
+
"La longitude est hors des limites du WGS84 (devrait être entre [-180, 180])"
|
|
31
|
+
|
|
32
|
+
#: geopic_tag_reader/reader.py:221
|
|
33
|
+
msgid "Skipping Mapillary date/time as it was not recognized:"
|
|
34
|
+
msgstr "La date/heure de Mapillary est ignorée car non-reconnue :"
|
|
35
|
+
|
|
36
|
+
#: geopic_tag_reader/reader.py:234
|
|
37
|
+
msgid "Contradicting heading values found, GPSImgDirection value is used"
|
|
38
|
+
msgstr ""
|
|
39
|
+
"Valeurs d'orientation contradictoires, la valeur de GPSImgDirection est "
|
|
40
|
+
"utilisée"
|
|
41
|
+
|
|
42
|
+
#: geopic_tag_reader/reader.py:345
|
|
43
|
+
msgid "No GPS coordinates or broken coordinates in picture EXIF tags"
|
|
44
|
+
msgstr "Coordonnees GPS absentes ou invalides dans les attributs EXIF de l'image"
|
|
45
|
+
|
|
46
|
+
#: geopic_tag_reader/reader.py:351
|
|
47
|
+
msgid "No valid date in picture EXIF tags"
|
|
48
|
+
msgstr "Aucune date valide dans les attributs EXIF de l'image"
|
|
49
|
+
|
|
50
|
+
#: geopic_tag_reader/reader.py:356
|
|
51
|
+
msgid " and "
|
|
52
|
+
msgstr " et "
|
|
53
|
+
|
|
54
|
+
#: geopic_tag_reader/reader.py:423
|
|
55
|
+
msgid "Not a valid list of fractions"
|
|
56
|
+
msgstr "Liste de fractions invalide"
|
|
57
|
+
|
|
58
|
+
#: geopic_tag_reader/reader.py:436 geopic_tag_reader/reader.py:465
|
|
59
|
+
msgid "GPSLatitudeRef not found, assuming GPSLatitudeRef is North"
|
|
60
|
+
msgstr "GPSLatitudeRef non-trouvé, utilisation du Nord par défaut"
|
|
61
|
+
|
|
62
|
+
#: geopic_tag_reader/reader.py:444
|
|
63
|
+
msgid "Broken GPS coordinates in picture EXIF tags"
|
|
64
|
+
msgstr "Coordonnées GPS invalides dans les attributs EXIF de l'image"
|
|
65
|
+
|
|
66
|
+
#: geopic_tag_reader/reader.py:447 geopic_tag_reader/reader.py:471
|
|
67
|
+
msgid "GPSLongitudeRef not found, assuming GPSLongitudeRef is East"
|
|
68
|
+
msgstr "GPSLongitudeRef non-trouvé, utilisation de l'Est par défaut"
|
|
69
|
+
|
|
70
|
+
#: geopic_tag_reader/reader.py:522
|
|
71
|
+
msgid "Precise timezone information not found, fallback to UTC"
|
|
72
|
+
msgstr ""
|
|
73
|
+
"Aucune information précise de fuseau horaire trouvée, UTC utilisé par défaut"
|
|
74
|
+
|
|
75
|
+
#: geopic_tag_reader/reader.py:527
|
|
76
|
+
msgid ""
|
|
77
|
+
"Precise timezone information not found (and no GPS coordinates to help), "
|
|
78
|
+
"fallback to UTC"
|
|
79
|
+
msgstr ""
|
|
80
|
+
"Aucune information précise de fuseau horaire trouvée (ni de coordonnées GPS "
|
|
81
|
+
"pour aider), UTC utilisé par défaut"
|
|
82
|
+
|
|
83
|
+
#: geopic_tag_reader/reader.py:530
|
|
84
|
+
#, python-brace-format
|
|
85
|
+
msgid ""
|
|
86
|
+
"Skipping original date/time (from {datefield}) as it was not recognized:"
|
|
87
|
+
msgstr ""
|
|
88
|
+
"Date/heure originale (issue de {datefield}) ignorée car elle n'a pas été "
|
|
89
|
+
"reconnue :"
|
|
90
|
+
|
|
91
|
+
#: geopic_tag_reader/reader.py:559
|
|
92
|
+
#, python-brace-format
|
|
93
|
+
msgid ""
|
|
94
|
+
"GPSTimeStamp and GPSDateTime don't contain supported time format (in {group} "
|
|
95
|
+
"group)"
|
|
96
|
+
msgstr ""
|
|
97
|
+
"GPSTimeStamp et GPSDateTime ne contiennent pas un format d'heure valide ("
|
|
98
|
+
"dans le groupe {group})"
|
|
99
|
+
|
|
100
|
+
#: geopic_tag_reader/reader.py:587
|
|
101
|
+
#, python-brace-format
|
|
102
|
+
msgid "Skipping GPS date/time ({group} group) as it was not recognized:"
|
|
103
|
+
msgstr ""
|
|
104
|
+
"Date/heure du GPS (groupe {group}) ignorée car elle n'a pas été reconnue :"
|
|
105
|
+
|
|
106
|
+
#: geopic_tag_reader/reader.py:609
|
|
107
|
+
#, python-brace-format
|
|
108
|
+
msgid ""
|
|
109
|
+
"Microseconds read from decimal seconds value ({microsecondsFromSeconds}) is "
|
|
110
|
+
"not matching value from EXIF field ({microseconds}). Max value will be kept."
|
|
111
|
+
msgstr ""
|
|
112
|
+
"La valeur de micro-secondes lue à partir des secondes en valeurs décimales "
|
|
113
|
+
"({microsecondsFromSeconds}) ne correspond pas au champ EXIF dédié "
|
|
114
|
+
"({microseconds}). La valeur la plus élevée est conservée."
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
# SOME DESCRIPTIVE TITLE.
|
|
2
|
+
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
|
3
|
+
# This file is distributed under the same license as the PACKAGE package.
|
|
4
|
+
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
|
5
|
+
#
|
|
6
|
+
#, fuzzy
|
|
7
|
+
msgid ""
|
|
8
|
+
msgstr ""
|
|
9
|
+
"Project-Id-Version: PACKAGE VERSION\n"
|
|
10
|
+
"Report-Msgid-Bugs-To: \n"
|
|
11
|
+
"POT-Creation-Date: 2024-06-25 08:45+0200\n"
|
|
12
|
+
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
|
13
|
+
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
|
14
|
+
"Language-Team: LANGUAGE <LL@li.org>\n"
|
|
15
|
+
"Language: \n"
|
|
16
|
+
"MIME-Version: 1.0\n"
|
|
17
|
+
"Content-Type: text/plain; charset=CHARSET\n"
|
|
18
|
+
"Content-Transfer-Encoding: 8bit\n"
|
|
19
|
+
|
|
20
|
+
#: geopic_tag_reader/reader.py:177
|
|
21
|
+
msgid "Read latitude is out of WGS84 bounds (should be in [-90, 90])"
|
|
22
|
+
msgstr ""
|
|
23
|
+
|
|
24
|
+
#: geopic_tag_reader/reader.py:179
|
|
25
|
+
msgid "Read longitude is out of WGS84 bounds (should be in [-180, 180])"
|
|
26
|
+
msgstr ""
|
|
27
|
+
|
|
28
|
+
#: geopic_tag_reader/reader.py:221
|
|
29
|
+
#, python-brace-format
|
|
30
|
+
msgid "Skipping Mapillary date/time as it was not recognized: {v}"
|
|
31
|
+
msgstr ""
|
|
32
|
+
|
|
33
|
+
#: geopic_tag_reader/reader.py:234
|
|
34
|
+
msgid "Contradicting heading values found, GPSImgDirection value is used"
|
|
35
|
+
msgstr ""
|
|
36
|
+
|
|
37
|
+
#: geopic_tag_reader/reader.py:345
|
|
38
|
+
msgid "No GPS coordinates or broken coordinates in picture EXIF tags"
|
|
39
|
+
msgstr ""
|
|
40
|
+
|
|
41
|
+
#: geopic_tag_reader/reader.py:351
|
|
42
|
+
msgid "No valid date in picture EXIF tags"
|
|
43
|
+
msgstr ""
|
|
44
|
+
|
|
45
|
+
#: geopic_tag_reader/reader.py:356
|
|
46
|
+
msgid "The picture is missing mandatory metadata:"
|
|
47
|
+
msgstr ""
|
|
48
|
+
|
|
49
|
+
#: geopic_tag_reader/reader.py:430
|
|
50
|
+
msgid "Not a valid list of fractions"
|
|
51
|
+
msgstr ""
|
|
52
|
+
|
|
53
|
+
#: geopic_tag_reader/reader.py:443 geopic_tag_reader/reader.py:472
|
|
54
|
+
msgid "GPSLatitudeRef not found, assuming GPSLatitudeRef is North"
|
|
55
|
+
msgstr ""
|
|
56
|
+
|
|
57
|
+
#: geopic_tag_reader/reader.py:451
|
|
58
|
+
msgid "Broken GPS coordinates in picture EXIF tags"
|
|
59
|
+
msgstr ""
|
|
60
|
+
|
|
61
|
+
#: geopic_tag_reader/reader.py:454 geopic_tag_reader/reader.py:478
|
|
62
|
+
msgid "GPSLongitudeRef not found, assuming GPSLongitudeRef is East"
|
|
63
|
+
msgstr ""
|
|
64
|
+
|
|
65
|
+
#: geopic_tag_reader/reader.py:529
|
|
66
|
+
msgid "Precise timezone information not found, fallback to UTC"
|
|
67
|
+
msgstr ""
|
|
68
|
+
|
|
69
|
+
#: geopic_tag_reader/reader.py:534
|
|
70
|
+
msgid ""
|
|
71
|
+
"Precise timezone information not found (and no GPS coordinates to help), "
|
|
72
|
+
"fallback to UTC"
|
|
73
|
+
msgstr ""
|
|
74
|
+
|
|
75
|
+
#: geopic_tag_reader/reader.py:538
|
|
76
|
+
#, python-brace-format
|
|
77
|
+
msgid ""
|
|
78
|
+
"Skipping original date/time (from {datefield}) as it was not recognized: {v}"
|
|
79
|
+
msgstr ""
|
|
80
|
+
|
|
81
|
+
#: geopic_tag_reader/reader.py:572
|
|
82
|
+
#, python-brace-format
|
|
83
|
+
msgid ""
|
|
84
|
+
"GPSTimeStamp and GPSDateTime don't contain supported time format (in {group} "
|
|
85
|
+
"group)"
|
|
86
|
+
msgstr ""
|
|
87
|
+
|
|
88
|
+
#: geopic_tag_reader/reader.py:602
|
|
89
|
+
#, python-brace-format
|
|
90
|
+
msgid "Skipping GPS date/time ({group} group) as it was not recognized: {v}"
|
|
91
|
+
msgstr ""
|
|
92
|
+
|
|
93
|
+
#: geopic_tag_reader/reader.py:628
|
|
94
|
+
#, python-brace-format
|
|
95
|
+
msgid ""
|
|
96
|
+
"Microseconds read from decimal seconds value ({microsecondsFromSeconds}) is "
|
|
97
|
+
"not matching value from EXIF field ({microseconds}). Max value will be kept."
|
|
98
|
+
msgstr ""
|
|
99
|
+
|
|
100
|
+
#: geopic_tag_reader/writer.py:15
|
|
101
|
+
msgid ""
|
|
102
|
+
"Impossible to write the exif tags without the '[write-exif]' dependency "
|
|
103
|
+
"(that will need to install libexiv2).\n"
|
|
104
|
+
"Install this package with `pip install geopic-tag-reader[write-exif]` to use "
|
|
105
|
+
"this function"
|
|
106
|
+
msgstr ""
|
|
107
|
+
|
|
108
|
+
#: geopic_tag_reader/writer.py:131
|
|
109
|
+
#, python-brace-format
|
|
110
|
+
msgid "Unsupported key in additional tags ({k})"
|
|
111
|
+
msgstr ""
|
geopic_tag_reader/writer.py
CHANGED
|
@@ -5,13 +5,16 @@ from geopic_tag_reader.model import PictureType
|
|
|
5
5
|
from enum import Enum
|
|
6
6
|
import timezonefinder # type: ignore
|
|
7
7
|
import pytz
|
|
8
|
+
from geopic_tag_reader.i18n import _
|
|
8
9
|
|
|
9
10
|
try:
|
|
10
11
|
import pyexiv2 # type: ignore
|
|
11
12
|
except ImportError:
|
|
12
13
|
raise Exception(
|
|
13
|
-
|
|
14
|
+
_(
|
|
15
|
+
"""Impossible to write the exif tags without the '[write-exif]' dependency (that will need to install libexiv2).
|
|
14
16
|
Install this package with `pip install geopic-tag-reader[write-exif]` to use this function"""
|
|
17
|
+
)
|
|
15
18
|
)
|
|
16
19
|
|
|
17
20
|
tz_finder = timezonefinder.TimezoneFinder()
|
|
@@ -125,7 +128,7 @@ def writePictureMetadata(picture: bytes, metadata: PictureMetadata) -> bytes:
|
|
|
125
128
|
elif k.startswith("Exif."):
|
|
126
129
|
updated_exif.update({k: v})
|
|
127
130
|
else:
|
|
128
|
-
raise UnsupportedExifTagException(
|
|
131
|
+
raise UnsupportedExifTagException(_("Unsupported key in additional tags ({k})").format(k=k))
|
|
129
132
|
|
|
130
133
|
if updated_exif:
|
|
131
134
|
img.modify_exif(updated_exif)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: geopic-tag-reader
|
|
3
|
-
Version: 1.1.
|
|
3
|
+
Version: 1.1.2
|
|
4
4
|
Summary: GeoPicTagReader
|
|
5
5
|
Author-email: Adrien PAVIE <panieravide@riseup.net>
|
|
6
6
|
Requires-Python: >=3.8
|
|
@@ -17,39 +17,26 @@ Requires-Dist: black ~= 24.3 ; extra == "dev"
|
|
|
17
17
|
Requires-Dist: mypy ~= 1.9 ; extra == "dev"
|
|
18
18
|
Requires-Dist: pytest ~= 7.2.0 ; extra == "dev"
|
|
19
19
|
Requires-Dist: pytest-datafiles ~= 3.0 ; extra == "dev"
|
|
20
|
-
Requires-Dist: lazydocs ~= 0.4.8 ; extra == "dev"
|
|
21
20
|
Requires-Dist: types-xmltodict ~= 0.13 ; extra == "dev"
|
|
22
21
|
Requires-Dist: pre-commit ~= 3.3.3 ; extra == "dev"
|
|
22
|
+
Requires-Dist: mkdocs-material ~= 9.5.21 ; extra == "docs"
|
|
23
|
+
Requires-Dist: mkdocstrings[python] ~= 0.25.1 ; extra == "docs"
|
|
23
24
|
Requires-Dist: python-dateutil ~= 2.8.2 ; extra == "write-exif"
|
|
24
|
-
|
|
25
|
+
Requires-Dist: types-python-dateutil ~= 2.9.0.20240316 ; extra == "write-exif"
|
|
26
|
+
Project-URL: Home, https://gitlab.com/panoramax/server/geo-picture-tag-reader
|
|
25
27
|
Provides-Extra: build
|
|
26
28
|
Provides-Extra: dev
|
|
29
|
+
Provides-Extra: docs
|
|
27
30
|
Provides-Extra: write-exif
|
|
28
31
|
|
|
29
|
-
#  Panoramax
|
|
30
33
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
➡️ __Give it a try__ at [panoramax.ign.fr](https://panoramax.ign.fr/) or [geovisio.fr](https://geovisio.fr/viewer) !
|
|
34
|
-
|
|
35
|
-
## 📦 Components
|
|
36
|
-
|
|
37
|
-
GeoVisio is __modular__ and made of several components, each of them standardized and ♻️ replaceable.
|
|
38
|
-
|
|
39
|
-

|
|
40
|
-
|
|
41
|
-
All of them are 📖 __open-source__ and available online:
|
|
42
|
-
|
|
43
|
-
| 🌐 Server | 💻 Client |
|
|
44
|
-
|:-----------------------------------------------------------------------:|:----------------------------------------------------:|
|
|
45
|
-
| [API](https://gitlab.com/geovisio/api) | [Website](https://gitlab.com/geovisio/website) |
|
|
46
|
-
| [Blur API](https://gitlab.com/geovisio/blurring) | [Web viewer](https://gitlab.com/geovisio/web-viewer) |
|
|
47
|
-
| [GeoPic Tag Reader](https://gitlab.com/geovisio/geo-picture-tag-reader) | [Command line](https://gitlab.com/geovisio/cli) |
|
|
34
|
+
__Panoramax__ is a digital resource for sharing and exploiting 📍📷 field photos. Anyone can take photographs of places visible from the public streets and contribute them to the Panoramax database. This data is then freely accessible and reusable by all. More information available at [gitlab.com/panoramax](https://gitlab.com/panoramax) and [panoramax.fr](https://panoramax.fr/).
|
|
48
35
|
|
|
49
36
|
|
|
50
37
|
# 📷 GeoPic Tag Reader
|
|
51
38
|
|
|
52
|
-
This repository only contains the Python library to __read and write standardized metadata__ from geolocated pictures EXIF metadata.
|
|
39
|
+
This repository only contains the Python library to __read and write standardized metadata__ from geolocated pictures EXIF metadata. It can be used completely apart from all GeoVisio/Panoramax components for your own projects and needs.
|
|
53
40
|
|
|
54
41
|
## Features
|
|
55
42
|
|
|
@@ -71,7 +58,7 @@ geopic-tag-reader --help
|
|
|
71
58
|
|
|
72
59
|
To know more about install and other options, see [install documentation](./docs/Install.md).
|
|
73
60
|
|
|
74
|
-
If at some point you're lost or need help, you can contact us through [issues](https://gitlab.com/
|
|
61
|
+
If at some point you're lost or need help, you can contact us through [issues](https://gitlab.com/panoramax/server/geo-picture-tag-reader/-/issues) or by [email](mailto:panieravide@riseup.net).
|
|
75
62
|
|
|
76
63
|
|
|
77
64
|
## Usage
|
|
@@ -137,26 +124,12 @@ editedImg.close()
|
|
|
137
124
|
|
|
138
125
|
## Contributing
|
|
139
126
|
|
|
140
|
-
Pull requests are welcome. For major changes, please open an [issue](https://gitlab.com/
|
|
127
|
+
Pull requests are welcome. For major changes, please open an [issue](https://gitlab.com/panoramax/server/geo-picture-tag-reader/-/issues) first to discuss what you would like to change.
|
|
141
128
|
|
|
142
129
|
More information about developing is available in [documentation](./docs/Develop.md).
|
|
143
130
|
|
|
144
131
|
|
|
145
|
-
## 🤗 Special thanks
|
|
146
|
-
|
|
147
|
-

|
|
148
|
-
|
|
149
|
-
GeoVisio was made possible thanks to a group of ✨ __amazing__ people ✨ :
|
|
150
|
-
|
|
151
|
-
- __[GéoVélo](https://geovelo.fr/)__ team, for 💶 funding initial development and for 🔍 testing/improving software
|
|
152
|
-
- __[Carto Cité](https://cartocite.fr/)__ team (in particular Antoine Riche), for 💶 funding improvements on viewer (map browser, flat pictures support)
|
|
153
|
-
- __[La Fabrique des Géocommuns (IGN)](https://www.ign.fr/institut/la-fabrique-des-geocommuns-incubateur-de-communs-lign)__ for offering long-term support and funding the [Panoramax](https://panoramax.fr/) initiative and core team (Camille Salou, Mathilde Ferrey, Christian Quest, Antoine Desbordes, Jean Andreani, Adrien Pavie)
|
|
154
|
-
- Many _many_ __wonderful people__ who worked on various parts of GeoVisio or core dependencies we use : 🧙 Stéphane Péneau, 🎚 Albin Calais & Cyrille Giquello, 📷 [Damien Sorel](https://www.strangeplanet.fr/), Pascal Rhod, Nick Whitelegg...
|
|
155
|
-
- __[Adrien Pavie](https://pavie.info/)__, for ⚙️ initial development of GeoVisio
|
|
156
|
-
- And you all ✨ __GeoVisio users__ for making this project useful !
|
|
157
|
-
|
|
158
|
-
|
|
159
132
|
## ⚖️ License
|
|
160
133
|
|
|
161
|
-
Copyright (c)
|
|
134
|
+
Copyright (c) Panoramax team 2022-2024, [released under MIT license](https://gitlab.com/panoramax/server/geo-picture-tag-reader/-/blob/main/LICENSE).
|
|
162
135
|
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
geopic_tag_reader/__init__.py,sha256=DCAt2kbPER8vsAuxzbjuzgbgYxV4aajpxsaPx--ZQ28,47
|
|
2
|
+
geopic_tag_reader/camera.py,sha256=Nw6dQjnrUCCOXujjk8Y7IwjJPMuDf4DAGCmHk0LDfEg,1975
|
|
3
|
+
geopic_tag_reader/i18n.py,sha256=MnhttLwppXnioXYUdlTi1J9SPtSKhaHc9ARYtsS5t-M,303
|
|
4
|
+
geopic_tag_reader/main.py,sha256=ZEZaZEeaDxRjrVMwhR5lUYJWKkUcjd8avjqm7JxJdhM,3219
|
|
5
|
+
geopic_tag_reader/model.py,sha256=rsWVE3T1kpNsKXX8iv6xb_3PCVY6Ea7iU9WOqUgXklU,129
|
|
6
|
+
geopic_tag_reader/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
7
|
+
geopic_tag_reader/reader.py,sha256=lHAMafZK7rCFsO1joCXGrbjyYJfgwab7dQF-eKFLRHs,25337
|
|
8
|
+
geopic_tag_reader/writer.py,sha256=gUvs2fVe7VIMzsT6ZGnXOiKqtsTgndDaJeTTCYnOpXQ,8748
|
|
9
|
+
geopic_tag_reader/translations/geopic_tag_reader.pot,sha256=-Z6YYskO_jYKXGJssbfigAixHMcAXylNAMKebcjFCXY,3198
|
|
10
|
+
geopic_tag_reader/translations/fr/LC_MESSAGES/geopic_tag_reader.po,sha256=QxuV0AYxOAVCI4xaKDDCvgUfeym6oRQC2YeRJpI9i9c,4223
|
|
11
|
+
geopic_tag_reader-1.1.2.dist-info/entry_points.txt,sha256=c9YwjCNhxveDf-61_aSRlzcpoutvM6KQCerlzaVt_JU,64
|
|
12
|
+
geopic_tag_reader-1.1.2.dist-info/LICENSE,sha256=oHWDwXkJJb9zJzThMN3F9Li4yFhz1qxOUByouY7L3bI,1070
|
|
13
|
+
geopic_tag_reader-1.1.2.dist-info/WHEEL,sha256=EZbGkh7Ie4PoZfRQ8I0ZuP9VklN_TvcZ6DSE5Uar4z4,81
|
|
14
|
+
geopic_tag_reader-1.1.2.dist-info/METADATA,sha256=fH9KBmz593jrgLNiRrYrWYH2gSWBi_xPXghP22v_92k,4578
|
|
15
|
+
geopic_tag_reader-1.1.2.dist-info/RECORD,,
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
geopic_tag_reader/__init__.py,sha256=7hT1At7Ce4FtNeMuBZa7cDah_cJoIhJrnQWbEAF0BE8,47
|
|
2
|
-
geopic_tag_reader/camera.py,sha256=2Sr0jAt3RXUWazYMnkwF6J6lVnKvSp7Ac8g7yOHehVA,1643
|
|
3
|
-
geopic_tag_reader/main.py,sha256=ZEZaZEeaDxRjrVMwhR5lUYJWKkUcjd8avjqm7JxJdhM,3219
|
|
4
|
-
geopic_tag_reader/model.py,sha256=rsWVE3T1kpNsKXX8iv6xb_3PCVY6Ea7iU9WOqUgXklU,129
|
|
5
|
-
geopic_tag_reader/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
6
|
-
geopic_tag_reader/reader.py,sha256=4yoQU-ljOgLmaH_hc1m4o1YkSNgaPfM38NVmiM7rpbE,24543
|
|
7
|
-
geopic_tag_reader/writer.py,sha256=QmQqQpWgb6AL3Y0Kuzy7PF1asUsTVDq9buwJXfFSRq8,8672
|
|
8
|
-
geopic_tag_reader-1.1.1.dist-info/entry_points.txt,sha256=c9YwjCNhxveDf-61_aSRlzcpoutvM6KQCerlzaVt_JU,64
|
|
9
|
-
geopic_tag_reader-1.1.1.dist-info/LICENSE,sha256=oHWDwXkJJb9zJzThMN3F9Li4yFhz1qxOUByouY7L3bI,1070
|
|
10
|
-
geopic_tag_reader-1.1.1.dist-info/WHEEL,sha256=EZbGkh7Ie4PoZfRQ8I0ZuP9VklN_TvcZ6DSE5Uar4z4,81
|
|
11
|
-
geopic_tag_reader-1.1.1.dist-info/METADATA,sha256=iMhClAI5r1h2jpB_o-dwcSP3QVz4PuBPf4jWmZ_10Ks,6303
|
|
12
|
-
geopic_tag_reader-1.1.1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|