geopic-tag-reader 1.1.0__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/main.py +2 -0
- geopic_tag_reader/reader.py +87 -27
- 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.0.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.0.dist-info/RECORD +0 -12
- {geopic_tag_reader-1.1.0.dist-info → geopic_tag_reader-1.1.2.dist-info}/LICENSE +0 -0
- {geopic_tag_reader-1.1.0.dist-info → geopic_tag_reader-1.1.2.dist-info}/WHEEL +0 -0
- {geopic_tag_reader-1.1.0.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/main.py
CHANGED
|
@@ -29,6 +29,8 @@ def read(
|
|
|
29
29
|
print("Model:", metadata.model)
|
|
30
30
|
print("Focal length:", metadata.focal_length)
|
|
31
31
|
print("Crop parameters:", metadata.crop)
|
|
32
|
+
print("Pitch:", metadata.pitch)
|
|
33
|
+
print("Roll:", metadata.roll)
|
|
32
34
|
|
|
33
35
|
if len(metadata.tagreader_warnings) > 0:
|
|
34
36
|
print("Warnings raised by reader:")
|
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
|
|
@@ -46,7 +47,7 @@ class GeoPicTags:
|
|
|
46
47
|
lat (float): GPS Latitude (in WGS84)
|
|
47
48
|
lon (float): GPS Longitude (in WGS84)
|
|
48
49
|
ts (datetime): The capture date (date & time with timezone)
|
|
49
|
-
heading (int): Picture heading (in degrees, North = 0°, East = 90°, South = 180°, West = 270°)
|
|
50
|
+
heading (int): Picture heading/yaw (in degrees, North = 0°, East = 90°, South = 180°, West = 270°)
|
|
50
51
|
type (str): The kind of picture (flat, equirectangular)
|
|
51
52
|
make (str): The camera manufacturer name
|
|
52
53
|
model (str): The camera model name
|
|
@@ -55,6 +56,8 @@ class GeoPicTags:
|
|
|
55
56
|
exif (dict[str, str]): Raw EXIF tags from picture (following Exiv2 naming scheme, see https://exiv2.org/metadata.html)
|
|
56
57
|
tagreader_warnings (list[str]): List of thrown warnings during metadata reading
|
|
57
58
|
altitude (float): altitude (in m) (optional)
|
|
59
|
+
pitch (float): Picture pitch angle, compared to horizon (in degrees, bottom = -90°, horizon = 0°, top = 90°)
|
|
60
|
+
roll (float): Picture roll angle, on a right/left axis (in degrees, left-arm down = -90°, flat = 0°, right-arm down = 90°)
|
|
58
61
|
|
|
59
62
|
|
|
60
63
|
Implementation note: this needs to be sync with the PartialGeoPicTags structure
|
|
@@ -72,6 +75,8 @@ class GeoPicTags:
|
|
|
72
75
|
exif: Dict[str, str] = field(default_factory=lambda: {})
|
|
73
76
|
tagreader_warnings: List[str] = field(default_factory=lambda: [])
|
|
74
77
|
altitude: Optional[float] = None
|
|
78
|
+
pitch: Optional[float] = None
|
|
79
|
+
roll: Optional[float] = None
|
|
75
80
|
|
|
76
81
|
|
|
77
82
|
class InvalidExifException(Exception):
|
|
@@ -100,6 +105,8 @@ class PartialGeoPicTags:
|
|
|
100
105
|
exif: Dict[str, str] = field(default_factory=lambda: {})
|
|
101
106
|
tagreader_warnings: List[str] = field(default_factory=lambda: [])
|
|
102
107
|
altitude: Optional[float] = None
|
|
108
|
+
pitch: Optional[float] = None
|
|
109
|
+
roll: Optional[float] = None
|
|
103
110
|
|
|
104
111
|
|
|
105
112
|
class PartialExifException(Exception):
|
|
@@ -167,9 +174,9 @@ def readPictureMetadata(picture: bytes) -> GeoPicTags:
|
|
|
167
174
|
|
|
168
175
|
# Check coordinates validity
|
|
169
176
|
if lat is not None and (lat < -90 or lat > 90):
|
|
170
|
-
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])"))
|
|
171
178
|
if lon is not None and (lon < -180 or lon > 180):
|
|
172
|
-
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])"))
|
|
173
180
|
|
|
174
181
|
# Parse date/time
|
|
175
182
|
d, llw = decodeGPSDateTime(data, "Exif.GPSInfo", lat, lon)
|
|
@@ -211,9 +218,9 @@ def readPictureMetadata(picture: bytes) -> GeoPicTags:
|
|
|
211
218
|
)
|
|
212
219
|
|
|
213
220
|
except Exception as e:
|
|
214
|
-
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"]))
|
|
215
222
|
|
|
216
|
-
# Heading
|
|
223
|
+
# Heading/Yaw
|
|
217
224
|
heading = None
|
|
218
225
|
if isExifTagUsable(data, "Xmp.GPano.PoseHeadingDegrees", float) and isExifTagUsable(data, "Exif.GPSInfo.GPSImgDirection", Fraction):
|
|
219
226
|
gpsDir = int(round(float(Fraction(data["Exif.GPSInfo.GPSImgDirection"]))))
|
|
@@ -224,7 +231,7 @@ def readPictureMetadata(picture: bytes) -> GeoPicTags:
|
|
|
224
231
|
heading = gpanoHeading
|
|
225
232
|
else:
|
|
226
233
|
if gpsDir != gpanoHeading:
|
|
227
|
-
warnings.append("Contradicting heading values found, GPSImgDirection value is used")
|
|
234
|
+
warnings.append(_("Contradicting heading values found, GPSImgDirection value is used"))
|
|
228
235
|
heading = gpsDir
|
|
229
236
|
|
|
230
237
|
elif isExifTagUsable(data, "Xmp.GPano.PoseHeadingDegrees", float):
|
|
@@ -236,6 +243,35 @@ def readPictureMetadata(picture: bytes) -> GeoPicTags:
|
|
|
236
243
|
elif "MAPCompassHeading" in data and isExifTagUsable(data["MAPCompassHeading"], "TrueHeading", float):
|
|
237
244
|
heading = int(round(float(data["MAPCompassHeading"]["TrueHeading"])))
|
|
238
245
|
|
|
246
|
+
# Pitch & roll
|
|
247
|
+
pitch = None
|
|
248
|
+
roll = None
|
|
249
|
+
exifPRFields = ["Xmp.Camera.$$", "Exif.GPSInfo.GPS$$", "Xmp.GPano.Pose$$Degrees", "Xmp.GPano.InitialView$$Degrees"]
|
|
250
|
+
# For each potential EXIF field
|
|
251
|
+
for exifField in exifPRFields:
|
|
252
|
+
# Try out both Pitch & Roll variants
|
|
253
|
+
for checkField in ["Pitch", "Roll"]:
|
|
254
|
+
exifCheckField = exifField.replace("$$", checkField)
|
|
255
|
+
foundValue = None
|
|
256
|
+
# Look for float or fraction
|
|
257
|
+
if isExifTagUsable(data, exifCheckField, float):
|
|
258
|
+
foundValue = float(data[exifCheckField])
|
|
259
|
+
elif isExifTagUsable(data, exifCheckField, Fraction):
|
|
260
|
+
foundValue = float(Fraction(data[exifCheckField]))
|
|
261
|
+
|
|
262
|
+
# Save to correct variable (if not already set)
|
|
263
|
+
if foundValue is not None:
|
|
264
|
+
if checkField == "Pitch":
|
|
265
|
+
if pitch is None:
|
|
266
|
+
pitch = foundValue
|
|
267
|
+
else:
|
|
268
|
+
continue
|
|
269
|
+
elif checkField == "Roll":
|
|
270
|
+
if roll is None:
|
|
271
|
+
roll = foundValue
|
|
272
|
+
else:
|
|
273
|
+
continue
|
|
274
|
+
|
|
239
275
|
# Make and model
|
|
240
276
|
make = data.get("Exif.Image.Make") or data.get("MAPDeviceMake")
|
|
241
277
|
model = data.get("Exif.Image.Model") or data.get("MAPDeviceModel")
|
|
@@ -306,18 +342,25 @@ def readPictureMetadata(picture: bytes) -> GeoPicTags:
|
|
|
306
342
|
errors = []
|
|
307
343
|
missing_fields = set()
|
|
308
344
|
if not lat or not lon:
|
|
309
|
-
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"))
|
|
310
346
|
if not lat:
|
|
311
347
|
missing_fields.add("lat")
|
|
312
348
|
if not lon:
|
|
313
349
|
missing_fields.add("lon")
|
|
314
350
|
if d is None:
|
|
315
|
-
errors.append("No valid date in picture EXIF tags")
|
|
351
|
+
errors.append(_("No valid date in picture EXIF tags"))
|
|
316
352
|
missing_fields.add("datetime")
|
|
317
353
|
|
|
318
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
|
+
|
|
319
362
|
raise PartialExifException(
|
|
320
|
-
|
|
363
|
+
listOfErrors,
|
|
321
364
|
missing_fields,
|
|
322
365
|
PartialGeoPicTags(
|
|
323
366
|
lat,
|
|
@@ -332,6 +375,8 @@ def readPictureMetadata(picture: bytes) -> GeoPicTags:
|
|
|
332
375
|
exif=data,
|
|
333
376
|
tagreader_warnings=warnings,
|
|
334
377
|
altitude=altitude,
|
|
378
|
+
pitch=pitch,
|
|
379
|
+
roll=roll,
|
|
335
380
|
),
|
|
336
381
|
)
|
|
337
382
|
|
|
@@ -349,6 +394,8 @@ def readPictureMetadata(picture: bytes) -> GeoPicTags:
|
|
|
349
394
|
exif=data,
|
|
350
395
|
tagreader_warnings=warnings,
|
|
351
396
|
altitude=altitude,
|
|
397
|
+
pitch=pitch,
|
|
398
|
+
roll=roll,
|
|
352
399
|
)
|
|
353
400
|
|
|
354
401
|
|
|
@@ -380,7 +427,7 @@ def decodeManyFractions(value: str) -> List[Fraction]:
|
|
|
380
427
|
return vals
|
|
381
428
|
|
|
382
429
|
except:
|
|
383
|
-
raise ValueError("Not a valid list of fractions")
|
|
430
|
+
raise ValueError(_("Not a valid list of fractions"))
|
|
384
431
|
|
|
385
432
|
|
|
386
433
|
def decodeLatLon(data: dict, group: str) -> Tuple[Optional[float], Optional[float], List[str]]:
|
|
@@ -393,7 +440,7 @@ def decodeLatLon(data: dict, group: str) -> Tuple[Optional[float], Optional[floa
|
|
|
393
440
|
latRaw = decodeManyFractions(data[f"{group}.GPSLatitude"])
|
|
394
441
|
if len(latRaw) == 3:
|
|
395
442
|
if not isExifTagUsable(data, f"{group}.GPSLatitudeRef"):
|
|
396
|
-
warnings.append("GPSLatitudeRef not found, assuming GPSLatitudeRef is North")
|
|
443
|
+
warnings.append(_("GPSLatitudeRef not found, assuming GPSLatitudeRef is North"))
|
|
397
444
|
latRef = 1
|
|
398
445
|
else:
|
|
399
446
|
latRef = -1 if data[f"{group}.GPSLatitudeRef"].startswith("S") else 1
|
|
@@ -401,10 +448,10 @@ def decodeLatLon(data: dict, group: str) -> Tuple[Optional[float], Optional[floa
|
|
|
401
448
|
|
|
402
449
|
lonRaw = decodeManyFractions(data[f"{group}.GPSLongitude"])
|
|
403
450
|
if len(lonRaw) != 3:
|
|
404
|
-
raise InvalidExifException("Broken GPS coordinates in picture EXIF tags")
|
|
451
|
+
raise InvalidExifException(_("Broken GPS coordinates in picture EXIF tags"))
|
|
405
452
|
|
|
406
453
|
if not isExifTagUsable(data, f"{group}.GPSLongitudeRef"):
|
|
407
|
-
warnings.append("GPSLongitudeRef not found, assuming GPSLongitudeRef is East")
|
|
454
|
+
warnings.append(_("GPSLongitudeRef not found, assuming GPSLongitudeRef is East"))
|
|
408
455
|
lonRef = 1
|
|
409
456
|
else:
|
|
410
457
|
lonRef = -1 if data[f"{group}.GPSLongitudeRef"].startswith("W") else 1
|
|
@@ -422,13 +469,13 @@ def decodeLatLon(data: dict, group: str) -> Tuple[Optional[float], Optional[floa
|
|
|
422
469
|
if rawLat and rawLon:
|
|
423
470
|
latRef = 1
|
|
424
471
|
if not isExifTagUsable(data, f"{group}.GPSLatitudeRef"):
|
|
425
|
-
warnings.append("GPSLatitudeRef not found, assuming GPSLatitudeRef is North")
|
|
472
|
+
warnings.append(_("GPSLatitudeRef not found, assuming GPSLatitudeRef is North"))
|
|
426
473
|
else:
|
|
427
474
|
latRef = -1 if data[f"{group}.GPSLatitudeRef"].startswith("S") else 1
|
|
428
475
|
|
|
429
476
|
lonRef = 1
|
|
430
477
|
if not isExifTagUsable(data, f"{group}.GPSLongitudeRef"):
|
|
431
|
-
warnings.append("GPSLongitudeRef not found, assuming GPSLongitudeRef is East")
|
|
478
|
+
warnings.append(_("GPSLongitudeRef not found, assuming GPSLongitudeRef is East"))
|
|
432
479
|
else:
|
|
433
480
|
lonRef = -1 if data[f"{group}.GPSLongitudeRef"].startswith("W") else 1
|
|
434
481
|
|
|
@@ -479,15 +526,19 @@ def decodeDateTimeOriginal(
|
|
|
479
526
|
# Otherwise, default to UTC + warning
|
|
480
527
|
else:
|
|
481
528
|
d = d.replace(tzinfo=datetime.timezone.utc)
|
|
482
|
-
warnings.append("Precise timezone information not found, fallback to UTC")
|
|
529
|
+
warnings.append(_("Precise timezone information not found, fallback to UTC"))
|
|
483
530
|
|
|
484
531
|
# Otherwise, default to UTC + warning
|
|
485
532
|
else:
|
|
486
533
|
d = d.replace(tzinfo=datetime.timezone.utc)
|
|
487
|
-
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"))
|
|
488
535
|
|
|
489
536
|
except ValueError as e:
|
|
490
|
-
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
|
+
)
|
|
491
542
|
|
|
492
543
|
return (d, warnings)
|
|
493
544
|
|
|
@@ -516,16 +567,19 @@ def decodeGPSDateTime(
|
|
|
516
567
|
elif isExifTagUsable(data, f"{group}.GPSDateTime", List[Fraction]):
|
|
517
568
|
timeRaw = decodeManyFractions(data[f"{group}.GPSDateTime"])
|
|
518
569
|
else:
|
|
519
|
-
|
|
570
|
+
timeRaw = None
|
|
571
|
+
warnings.append(
|
|
572
|
+
_("GPSTimeStamp and GPSDateTime don't contain supported time format (in {group} group)").format(group=group)
|
|
573
|
+
)
|
|
520
574
|
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
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
|
+
)
|
|
525
580
|
|
|
526
|
-
|
|
581
|
+
warnings += msw
|
|
527
582
|
|
|
528
|
-
if timeRaw:
|
|
529
583
|
d = datetime.datetime.combine(
|
|
530
584
|
datetime.date.fromisoformat(dateRaw),
|
|
531
585
|
datetime.time(
|
|
@@ -544,7 +598,11 @@ def decodeGPSDateTime(
|
|
|
544
598
|
d = d.astimezone(pytz.timezone(tz_name))
|
|
545
599
|
|
|
546
600
|
except ValueError as e:
|
|
547
|
-
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
|
+
)
|
|
548
606
|
|
|
549
607
|
return (d, warnings)
|
|
550
608
|
|
|
@@ -566,7 +624,9 @@ def decodeSecondsAndMicroSeconds(secondsRaw: str, microsecondsRaw: str) -> Tuple
|
|
|
566
624
|
# Check if microseconds from decimal seconds is not mismatching microseconds from SubSecTime field
|
|
567
625
|
if microseconds != microsecondsFromSeconds and microseconds > 0 and microsecondsFromSeconds > 0:
|
|
568
626
|
warnings.append(
|
|
569
|
-
|
|
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)
|
|
570
630
|
)
|
|
571
631
|
microseconds = max(microseconds, microsecondsFromSeconds)
|
|
572
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=o8d20yL96tGKyj_0NXyBn_HJ2i1hofM-qTuKouf4ZkE,47
|
|
2
|
-
geopic_tag_reader/camera.py,sha256=2Sr0jAt3RXUWazYMnkwF6J6lVnKvSp7Ac8g7yOHehVA,1643
|
|
3
|
-
geopic_tag_reader/main.py,sha256=a0RmJIA0R5dTK1vzDZD3Q4MFFAiDv6pnRiFHjfIjeJU,3141
|
|
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=w19zJ9CvdJyk_UxWcYX2T0DkhdQmw2xMzlAo1sR1ir0,22867
|
|
7
|
-
geopic_tag_reader/writer.py,sha256=QmQqQpWgb6AL3Y0Kuzy7PF1asUsTVDq9buwJXfFSRq8,8672
|
|
8
|
-
geopic_tag_reader-1.1.0.dist-info/entry_points.txt,sha256=c9YwjCNhxveDf-61_aSRlzcpoutvM6KQCerlzaVt_JU,64
|
|
9
|
-
geopic_tag_reader-1.1.0.dist-info/LICENSE,sha256=oHWDwXkJJb9zJzThMN3F9Li4yFhz1qxOUByouY7L3bI,1070
|
|
10
|
-
geopic_tag_reader-1.1.0.dist-info/WHEEL,sha256=EZbGkh7Ie4PoZfRQ8I0ZuP9VklN_TvcZ6DSE5Uar4z4,81
|
|
11
|
-
geopic_tag_reader-1.1.0.dist-info/METADATA,sha256=DJ9OiZyvVGNMdveGev-V33kO9sqPPo-V9SADIezd0I4,6303
|
|
12
|
-
geopic_tag_reader-1.1.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|