geopic-tag-reader 1.0.4__tar.gz → 1.0.6__tar.gz

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.
Files changed (65) hide show
  1. {geopic_tag_reader-1.0.4 → geopic_tag_reader-1.0.6}/CHANGELOG.md +39 -14
  2. {geopic_tag_reader-1.0.4 → geopic_tag_reader-1.0.6}/Makefile +1 -1
  3. {geopic_tag_reader-1.0.4 → geopic_tag_reader-1.0.6}/PKG-INFO +7 -8
  4. {geopic_tag_reader-1.0.4 → geopic_tag_reader-1.0.6}/docs/API_USAGE.md +2 -2
  5. {geopic_tag_reader-1.0.4 → geopic_tag_reader-1.0.6}/docs/Install.md +1 -1
  6. {geopic_tag_reader-1.0.4 → geopic_tag_reader-1.0.6}/docs/camera.md +11 -4
  7. {geopic_tag_reader-1.0.4 → geopic_tag_reader-1.0.6}/docs/model.md +1 -3
  8. {geopic_tag_reader-1.0.4 → geopic_tag_reader-1.0.6}/geopic_tag_reader/__init__.py +2 -1
  9. {geopic_tag_reader-1.0.4 → geopic_tag_reader-1.0.6}/geopic_tag_reader/camera.py +11 -5
  10. {geopic_tag_reader-1.0.4 → geopic_tag_reader-1.0.6}/geopic_tag_reader/reader.py +2 -2
  11. {geopic_tag_reader-1.0.4 → geopic_tag_reader-1.0.6}/pyproject.toml +6 -8
  12. geopic_tag_reader-1.0.6/tests/fixtures/gopromax_flat.jpg +0 -0
  13. geopic_tag_reader-1.0.6/tests/fixtures/gps_date_slash.jpg +0 -0
  14. {geopic_tag_reader-1.0.4 → geopic_tag_reader-1.0.6}/tests/test_reader.py +46 -2
  15. {geopic_tag_reader-1.0.4 → geopic_tag_reader-1.0.6}/.gitignore +0 -0
  16. {geopic_tag_reader-1.0.4 → geopic_tag_reader-1.0.6}/.gitlab-ci.yml +0 -0
  17. {geopic_tag_reader-1.0.4 → geopic_tag_reader-1.0.6}/.pre-commit-config.yaml +0 -0
  18. {geopic_tag_reader-1.0.4 → geopic_tag_reader-1.0.6}/CODE_OF_CONDUCT.md +0 -0
  19. {geopic_tag_reader-1.0.4 → geopic_tag_reader-1.0.6}/LICENSE +0 -0
  20. {geopic_tag_reader-1.0.4 → geopic_tag_reader-1.0.6}/README.md +0 -0
  21. {geopic_tag_reader-1.0.4 → geopic_tag_reader-1.0.6}/docs/.pages +0 -0
  22. {geopic_tag_reader-1.0.4 → geopic_tag_reader-1.0.6}/docs/CLI_USAGE.md +0 -0
  23. {geopic_tag_reader-1.0.4 → geopic_tag_reader-1.0.6}/docs/Develop.md +0 -0
  24. {geopic_tag_reader-1.0.4 → geopic_tag_reader-1.0.6}/docs/reader.md +0 -0
  25. {geopic_tag_reader-1.0.4 → geopic_tag_reader-1.0.6}/docs/writer.md +0 -0
  26. {geopic_tag_reader-1.0.4 → geopic_tag_reader-1.0.6}/geopic_tag_reader/main.py +0 -0
  27. {geopic_tag_reader-1.0.4 → geopic_tag_reader-1.0.6}/geopic_tag_reader/model.py +0 -0
  28. {geopic_tag_reader-1.0.4 → geopic_tag_reader-1.0.6}/geopic_tag_reader/py.typed +0 -0
  29. {geopic_tag_reader-1.0.4 → geopic_tag_reader-1.0.6}/geopic_tag_reader/writer.py +0 -0
  30. {geopic_tag_reader-1.0.4 → geopic_tag_reader-1.0.6}/pytest.ini +0 -0
  31. {geopic_tag_reader-1.0.4 → geopic_tag_reader-1.0.6}/tests/__init__.py +0 -0
  32. {geopic_tag_reader-1.0.4 → geopic_tag_reader-1.0.6}/tests/conftest.py +0 -0
  33. {geopic_tag_reader-1.0.4 → geopic_tag_reader-1.0.6}/tests/fixtures/1.jpg +0 -0
  34. {geopic_tag_reader-1.0.4 → geopic_tag_reader-1.0.6}/tests/fixtures/IMG_20210720_144918.jpg +0 -0
  35. {geopic_tag_reader-1.0.4 → geopic_tag_reader-1.0.6}/tests/fixtures/IMG_20210720_161352.jpg +0 -0
  36. {geopic_tag_reader-1.0.4 → geopic_tag_reader-1.0.6}/tests/fixtures/a1.jpg +0 -0
  37. {geopic_tag_reader-1.0.4 → geopic_tag_reader-1.0.6}/tests/fixtures/b1.jpg +0 -0
  38. {geopic_tag_reader-1.0.4 → geopic_tag_reader-1.0.6}/tests/fixtures/broken_makernotes.jpg +0 -0
  39. {geopic_tag_reader-1.0.4 → geopic_tag_reader-1.0.6}/tests/fixtures/c1.jpg +0 -0
  40. {geopic_tag_reader-1.0.4 → geopic_tag_reader-1.0.6}/tests/fixtures/cropped.jpg +0 -0
  41. {geopic_tag_reader-1.0.4 → geopic_tag_reader-1.0.6}/tests/fixtures/d1.jpg +0 -0
  42. {geopic_tag_reader-1.0.4 → geopic_tag_reader-1.0.6}/tests/fixtures/datetime_ms_float.jpg +0 -0
  43. {geopic_tag_reader-1.0.4 → geopic_tag_reader-1.0.6}/tests/fixtures/datetime_offset.jpg +0 -0
  44. {geopic_tag_reader-1.0.4 → geopic_tag_reader-1.0.6}/tests/fixtures/e1.jpg +0 -0
  45. {geopic_tag_reader-1.0.4 → geopic_tag_reader-1.0.6}/tests/fixtures/flat.jpg +0 -0
  46. {geopic_tag_reader-1.0.4 → geopic_tag_reader-1.0.6}/tests/fixtures/gps_date_time_stamp.jpg +0 -0
  47. {geopic_tag_reader-1.0.4 → geopic_tag_reader-1.0.6}/tests/fixtures/img_Ricoh_Theta.jpg +0 -0
  48. {geopic_tag_reader-1.0.4 → geopic_tag_reader-1.0.6}/tests/fixtures/img_V4MPack.jpg +0 -0
  49. {geopic_tag_reader-1.0.4 → geopic_tag_reader-1.0.6}/tests/fixtures/img_categorisee.jpg +0 -0
  50. {geopic_tag_reader-1.0.4 → geopic_tag_reader-1.0.6}/tests/fixtures/img_datetimeoriginal.jpg +0 -0
  51. {geopic_tag_reader-1.0.4 → geopic_tag_reader-1.0.6}/tests/fixtures/img_gps_date_string.jpg +0 -0
  52. {geopic_tag_reader-1.0.4 → geopic_tag_reader-1.0.6}/tests/fixtures/img_gps_datestamp.jpg +0 -0
  53. {geopic_tag_reader-1.0.4 → geopic_tag_reader-1.0.6}/tests/fixtures/img_gps_sotm.jpg +0 -0
  54. {geopic_tag_reader-1.0.4 → geopic_tag_reader-1.0.6}/tests/fixtures/img_invalid_gps_date.jpg +0 -0
  55. {geopic_tag_reader-1.0.4 → geopic_tag_reader-1.0.6}/tests/fixtures/img_without_coord.jpg +0 -0
  56. {geopic_tag_reader-1.0.4 → geopic_tag_reader-1.0.6}/tests/fixtures/img_without_dt.jpg +0 -0
  57. {geopic_tag_reader-1.0.4 → geopic_tag_reader-1.0.6}/tests/fixtures/img_without_exif_tags.jpg +0 -0
  58. {geopic_tag_reader-1.0.4 → geopic_tag_reader-1.0.6}/tests/fixtures/insta360_date.jpg +0 -0
  59. {geopic_tag_reader-1.0.4 → geopic_tag_reader-1.0.6}/tests/fixtures/int_long_tag.jpg +0 -0
  60. {geopic_tag_reader-1.0.4 → geopic_tag_reader-1.0.6}/tests/fixtures/out_of_bounds_lat.jpg +0 -0
  61. {geopic_tag_reader-1.0.4 → geopic_tag_reader-1.0.6}/tests/fixtures/out_of_bounds_lon.jpg +0 -0
  62. {geopic_tag_reader-1.0.4 → geopic_tag_reader-1.0.6}/tests/fixtures/pic_with_float_lat.jpg +0 -0
  63. {geopic_tag_reader-1.0.4 → geopic_tag_reader-1.0.6}/tests/fixtures/ricoh_theta_no_projection.jpg +0 -0
  64. {geopic_tag_reader-1.0.4 → geopic_tag_reader-1.0.6}/tests/test_main.py +0 -0
  65. {geopic_tag_reader-1.0.4 → geopic_tag_reader-1.0.6}/tests/test_writer.py +0 -0
@@ -1,4 +1,5 @@
1
1
  # Changelog
2
+
2
3
  All notable changes to this project will be documented in this file.
3
4
 
4
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
@@ -6,130 +7,154 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
6
7
 
7
8
  ## [Unreleased]
8
9
 
10
+ ## [1.0.6] - 2024-04-02
11
+
12
+ ### Changed
13
+
14
+ - Bump some dependencies, the most important one being [typer](https://typer.tiangolo.com/) since it removes the need for typer-cli.
15
+
16
+ ## [1.0.5] - 2024-03-06
17
+
18
+ ### Fixed
19
+
20
+ - Automatic detection of 360° pictures based on make and model also checks for image dimensions (to avoid false positive, when 360° camera can also take flat pictures).
21
+ - Slash character in GPS date stamp was not correctly interpreted.
9
22
 
10
23
  ## [1.0.4] - 2024-02-12
11
24
 
12
25
  ### Changed
13
- - When using date/time not coming from GPS, offset time EXIF field are also read (`Exif.Photo.OffsetTimeOriginal` or `Exif.Photo.OffsetTime` depending on used date/time EXIF tag).
14
26
 
27
+ - When using date/time not coming from GPS, offset time EXIF field are also read (`Exif.Photo.OffsetTimeOriginal` or `Exif.Photo.OffsetTime` depending on used date/time EXIF tag).
15
28
 
16
29
  ## [1.0.3] - 2023-12-18
17
30
 
18
31
  ### Added
32
+
19
33
  - Support reading date from EXIF fields `Exif.Image.DateTime` and `Xmp.GPano.SourceImageCreateTime`.
20
34
  - Auto-detect if a picture is 360° based on make and model.
21
35
 
22
36
  ### Fixed
23
- - Avoid failures for pictures with invalid offset for maker notes (due to PyExiv2 log level).
24
37
 
38
+ - Avoid failures for pictures with invalid offset for maker notes (due to PyExiv2 log level).
25
39
 
26
40
  ## [1.0.2] - 2023-11-20
27
41
 
28
42
  ### Added
43
+
29
44
  - A warning is thrown when microseconds values between decimal seconds and sub-second time fields are not matching.
30
45
 
31
46
  ### Changed
32
- - Fraction values for date, time and GPS coordinates are supported.
33
47
 
48
+ - Fraction values for date, time and GPS coordinates are supported.
34
49
 
35
50
  ## [1.0.1] - 2023-11-17
36
51
 
37
52
  ### Fixed
38
- - `DateTimeOriginal` field wasn't correctly read when seconds value was decimal.
39
53
 
54
+ - `DateTimeOriginal` field wasn't correctly read when seconds value was decimal.
40
55
 
41
56
  ## [1.0.0] - 2023-10-18
42
57
 
43
58
  ### Added
59
+
44
60
  - Add subseconds to written metadata
45
61
  - Read altitude in metadata
46
62
  - Write direction and altitude metadata
47
63
  - Add `additional_exif` tags in `writePictureMetadata`
48
64
 
49
65
  ### Changed
50
- - EXIF list of tags now uses the [Exiv2](https://exiv2.org/metadata.html) notation (example `Exif.Image.Artist`) in returned data. To do this, pyexiv2 dependency is always necessary, and Pillow dependency has been removed. As a consequence, `readPictureMetadata` function __now takes in input `bytes`__ read from picture file instead of Pillow image. This is a breaking change.
51
- - Use overriden metadata is available to localize overriden capture_time
52
66
 
67
+ - EXIF list of tags now uses the [Exiv2](https://exiv2.org/metadata.html) notation (example `Exif.Image.Artist`) in returned data. To do this, pyexiv2 dependency is always necessary, and Pillow dependency has been removed. As a consequence, `readPictureMetadata` function **now takes in input `bytes`** read from picture file instead of Pillow image. This is a breaking change.
68
+ - Use overriden metadata is available to localize overriden capture_time
53
69
 
54
70
  ## [0.4.1] - 2023-09-08
55
71
 
56
72
  ### Added
57
- - Latitude and longitude values are checked to verify they fit into WGS84 projection bounds (-180, -90, 180, 90).
58
73
 
74
+ - Latitude and longitude values are checked to verify they fit into WGS84 projection bounds (-180, -90, 180, 90).
59
75
 
60
76
  ## [0.4.0] - 2023-09-01
61
77
 
62
78
  ### Added
79
+
63
80
  - When a picture does not contain a mandatory exif tag (coordinates or datetime), a `PartialExifException` is thrown containing some information about what has been parsed and what is missing.
64
81
 
65
82
  ## [0.3.1] - 2023-07-31
66
83
 
67
84
  ### Added
85
+
68
86
  - A way to write exif lon/lat and type tags.
69
87
 
70
88
  ## [0.3.0] - 2023-07-31
71
89
 
72
90
  ### Added
91
+
73
92
  - Support of any date/time separator for EXIF tag `DateTimeOriginal`
74
93
  - A way to write exif tags. To use this, you need to install this library with the extra `[write-exif]`.
75
94
 
76
-
77
95
  ## [0.2.0] - 2023-07-13
78
96
 
79
97
  ### Added
98
+
80
99
  - Support of cropped equirectangular panoramas
81
100
 
82
101
  ### Changed
102
+
83
103
  - Support python 3.8
84
104
 
85
105
  ## [0.1.3]
86
106
 
87
107
  ### Changed
108
+
88
109
  - Bump [Typer](typer.tiangolo.com/) version, and use fork of [Typer-cli](https://gitlab.com/geovisio/infra/typer-cli)
89
110
 
90
111
  ## [0.1.2]
91
112
 
92
113
  ### Added
93
- - Full typing support ([PEP 484](https://peps.python.org/pep-0484/) and [PEP 561](https://peps.python.org/pep-0561/))
94
114
 
115
+ - Full typing support ([PEP 484](https://peps.python.org/pep-0484/) and [PEP 561](https://peps.python.org/pep-0561/))
95
116
 
96
117
  ## [0.1.1]
97
118
 
98
119
  ### Added
99
- - Support of Mapillary tags stored in EXIF tag `ImageDescription`
100
120
 
121
+ - Support of Mapillary tags stored in EXIF tag `ImageDescription`
101
122
 
102
123
  ## [0.1.0]
103
124
 
104
125
  ### Added
126
+
105
127
  - If GPS Date or time can't be read, fallbacks to Original Date EXIF tag associated with a reader warning
106
128
  - New EXIF tags are supported: `GPSDateTime`
107
129
 
108
130
  ### Changed
131
+
109
132
  - `tag_reader:warning` property has been moved from EXIF, and is now available as a direct property named `tagreader_warnings` of `GeoPicTags` class
110
133
  - Reader now supports `GPSLatitude` and `GPSLongitude` stored as decimal values instead of tuple
111
134
  - Reader now supports reading `FocalLength` written in `NUMBER/NUMBER` format
112
135
  - If EXIF tags for heading `PoseHeadingDegrees` and `GPSImgDirection` have contradicting values, we use by default `GPSImgDirection` value and issue a warning, instead of raising an error
113
136
 
114
137
  ### Fixed
115
- - EXIF tag `SubsecTimeOriginal` was not correctly read due to a typo
116
138
 
139
+ - EXIF tag `SubsecTimeOriginal` was not correctly read due to a typo
117
140
 
118
141
  ## [0.0.2] - 2023-05-10
119
142
 
120
143
  ### Added
144
+
121
145
  - EXIF tag `UserComment` is now read and available in raw `exif` tags
122
146
  - If not set, `GPSLatitudeRef` defaults to North and `GPSLongitudeRef` defaults to East
123
147
  - A new `tag_reader:warning` property lists non-blocking warnings raised while reading EXIF tags
124
148
 
125
-
126
149
  ## [0.0.1] - 2023-03-31
127
150
 
128
151
  ### Added
129
- - EXIF tag reading methods extracted from [GeoVisio API](https://gitlab.com/geovisio/api)
130
152
 
153
+ - EXIF tag reading methods extracted from [GeoVisio API](https://gitlab.com/geovisio/api)
131
154
 
132
- [Unreleased]: https://gitlab.com/geovisio/geo-picture-tag-reader/-/compare/1.0.4...main
155
+ [Unreleased]: https://gitlab.com/geovisio/geo-picture-tag-reader/-/compare/1.0.6...main
156
+ [1.0.6]: https://gitlab.com/geovisio/geo-picture-tag-reader/-/compare/1.0.5...1.0.6
157
+ [1.0.5]: https://gitlab.com/geovisio/geo-picture-tag-reader/-/compare/1.0.4...1.0.5
133
158
  [1.0.4]: https://gitlab.com/geovisio/geo-picture-tag-reader/-/compare/1.0.3...1.0.4
134
159
  [1.0.3]: https://gitlab.com/geovisio/geo-picture-tag-reader/-/compare/1.0.2...1.0.3
135
160
  [1.0.2]: https://gitlab.com/geovisio/geo-picture-tag-reader/-/compare/1.0.1...1.0.2
@@ -14,7 +14,7 @@ fmt: ## Format code
14
14
  ci: type-check fmt test ## Run all check like the ci
15
15
 
16
16
  docs: ## Generates documentation from Typer embedded docs
17
- python -m typer_cli ./geopic_tag_reader/main.py utils docs --name geopic-tag-reader --output docs/CLI_USAGE.md
17
+ python -m typer ./geopic_tag_reader/main.py utils docs --name geopic-tag-reader --output docs/CLI_USAGE.md
18
18
  lazydocs --overview-file API_USAGE.md --ignored-modules main --output-path docs/ geopic_tag_reader/
19
19
 
20
20
  help: ## Print this help message
@@ -1,22 +1,21 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: geopic-tag-reader
3
- Version: 1.0.4
3
+ Version: 1.0.6
4
4
  Summary: GeoPicTagReader
5
5
  Author-email: Adrien PAVIE <panieravide@riseup.net>
6
6
  Requires-Python: >=3.8
7
7
  Description-Content-Type: text/markdown
8
8
  Classifier: License :: OSI Approved :: MIT License
9
- Requires-Dist: typer ~= 0.9.0
10
- Requires-Dist: xmltodict ~= 0.13.0
9
+ Requires-Dist: typer ~= 0.12
10
+ Requires-Dist: xmltodict ~= 0.13
11
11
  Requires-Dist: pyexiv2 == 2.8.3
12
12
  Requires-Dist: flit ~= 3.8.0 ; extra == "build"
13
- Requires-Dist: black ~= 22.8.0 ; extra == "dev"
14
- Requires-Dist: mypy ~= 1.0.0 ; extra == "dev"
13
+ Requires-Dist: black ~= 24.3 ; extra == "dev"
14
+ Requires-Dist: mypy ~= 1.9 ; extra == "dev"
15
15
  Requires-Dist: pytest ~= 7.2.0 ; extra == "dev"
16
- Requires-Dist: pytest-datafiles ~= 2.0.1 ; extra == "dev"
17
- Requires-Dist: typer-cli-forked ~= 0.0.14 ; extra == "dev"
16
+ Requires-Dist: pytest-datafiles ~= 3.0 ; extra == "dev"
18
17
  Requires-Dist: lazydocs ~= 0.4.8 ; extra == "dev"
19
- Requires-Dist: types-xmltodict ~= 0.13.0 ; extra == "dev"
18
+ Requires-Dist: types-xmltodict ~= 0.13 ; extra == "dev"
20
19
  Requires-Dist: pre-commit ~= 3.3.3 ; extra == "dev"
21
20
  Requires-Dist: timezonefinder == 6.2.0 ; extra == "write-exif"
22
21
  Requires-Dist: pytz ~= 2023.3 ; extra == "write-exif"
@@ -11,7 +11,7 @@
11
11
 
12
12
  ## Classes
13
13
 
14
- - [`model.PictureType`](./model.md#class-picturetype)
14
+ - [`model.PictureType`](./model.md#class-picturetype): An enumeration.
15
15
  - [`reader.CropValues`](./reader.md#class-cropvalues): Cropped equirectangular pictures metadata
16
16
  - [`reader.GeoPicTags`](./reader.md#class-geopictags): Tags associated to a geolocated picture
17
17
  - [`reader.InvalidExifException`](./reader.md#class-invalidexifexception): Exception for invalid EXIF information from image
@@ -24,7 +24,7 @@
24
24
 
25
25
  ## Functions
26
26
 
27
- - [`camera.is_360`](./camera.md#function-is_360): Checks if given camera is equirectangular (360°) based on its make and model.
27
+ - [`camera.is_360`](./camera.md#function-is_360): Checks if given camera is equirectangular (360°) based on its make, model and dimensions (width, height).
28
28
  - [`reader.decodeDateTimeOriginal`](./reader.md#function-decodedatetimeoriginal)
29
29
  - [`reader.decodeGPSDateTime`](./reader.md#function-decodegpsdatetime)
30
30
  - [`reader.decodeLatLon`](./reader.md#function-decodelatlon): Reads GPS info from given group to get latitude/longitude as float coordinates
@@ -5,7 +5,7 @@ GeoPicTagReader can be installed using two methods:
5
5
  - From [PyPI](https://pypi.org/project/geopic-tag-reader/), the Python central package repository
6
6
  - Using this [Git repository](https://gitlab.com/geovisio/geo-picture-tag-reader)
7
7
 
8
- GeoPicTagReader is compatible with all python version >= 3.8.
8
+ GeoPicTagReader is compatible with all python version >= 3.8. Note that, due to [Pyexiv2 dependency on a recent GLIBC version](https://github.com/LeoHsiao1/pyexiv2/issues/120), you have to make sure to run on a recent, up-to-date operating system.
9
9
 
10
10
  ## From PyPI
11
11
 
@@ -18,15 +18,22 @@
18
18
  ## <kbd>function</kbd> `is_360`
19
19
 
20
20
  ```python
21
- is_360(make: Optional[str], model: Optional[str]) → bool
21
+ is_360(
22
+ make: Optional[str] = None,
23
+ model: Optional[str] = None,
24
+ width: Optional[str] = None,
25
+ height: Optional[str] = None
26
+ ) → bool
22
27
  ```
23
28
 
24
- Checks if given camera is equirectangular (360°) based on its make and model.
29
+ Checks if given camera is equirectangular (360°) based on its make, model and dimensions (width, height).
25
30
 
26
- ``` is_360(None, None)```
31
+ ``` is_360()```
27
32
  False
28
- ``` is_360("GoPro", None)``` False ``` is_360("GoPro", "Max 360")```
33
+ ``` is_360("GoPro")``` False ``` is_360("GoPro", "Max 360")```
29
34
  True
35
+ ``` is_360("GoPro", "Max 360", "2048", "1024")``` True ``` is_360("GoPro", "Max 360", "1024", "768")```
36
+ False
30
37
 
31
38
 
32
39
 
@@ -14,9 +14,7 @@
14
14
  <a href="../geopic_tag_reader/model.py#L4"><img align="right" style="float:right;" src="https://img.shields.io/badge/-source-cccccc?style=flat-square"></a>
15
15
 
16
16
  ## <kbd>class</kbd> `PictureType`
17
-
18
-
19
-
17
+ An enumeration.
20
18
 
21
19
 
22
20
 
@@ -1,4 +1,5 @@
1
1
  """
2
2
  GeoPicTagReader
3
3
  """
4
- __version__ = "1.0.4"
4
+
5
+ __version__ = "1.0.6"
@@ -25,19 +25,25 @@ EQUIRECTANGULAR_MODELS: Dict[str, List[str]] = {
25
25
  }
26
26
 
27
27
 
28
- def is_360(make: Optional[str], model: Optional[str]) -> bool:
28
+ def is_360(make: Optional[str] = None, model: Optional[str] = None, width: Optional[str] = None, height: Optional[str] = None) -> bool:
29
29
  """
30
- Checks if given camera is equirectangular (360°) based on its make and model.
30
+ Checks if given camera is equirectangular (360°) based on its make, model and dimensions (width, height).
31
31
 
32
- >>> is_360(None, None)
32
+ >>> is_360()
33
33
  False
34
- >>> is_360("GoPro", None)
34
+ >>> is_360("GoPro")
35
35
  False
36
36
  >>> is_360("GoPro", "Max 360")
37
37
  True
38
+ >>> is_360("GoPro", "Max 360", "2048", "1024")
39
+ True
40
+ >>> is_360("GoPro", "Max 360", "1024", "768")
41
+ False
38
42
  """
39
43
 
40
44
  if not make or not model:
41
45
  return False
42
46
 
43
- return any(model.startswith(potentialModel) for potentialModel in EQUIRECTANGULAR_MODELS.get(make, []))
47
+ return any(model.startswith(potentialModel) for potentialModel in EQUIRECTANGULAR_MODELS.get(make, [])) and (
48
+ (width is None or height is None) or int(width) == 2 * int(height)
49
+ )
@@ -281,7 +281,7 @@ def readPictureMetadata(picture: bytes) -> GeoPicTags:
281
281
  if isExifTagUsable(data, "Xmp.GPano.ProjectionType"):
282
282
  pic_type = data["Xmp.GPano.ProjectionType"]
283
283
  # 360° based on known models
284
- elif camera.is_360(make, model):
284
+ elif camera.is_360(make, model, data.get("Exif.Photo.PixelXDimension"), data.get("Exif.Photo.PixelYDimension")):
285
285
  pic_type = "equirectangular"
286
286
  # Flat by default
287
287
  else:
@@ -473,7 +473,7 @@ def decodeGPSDateTime(data: dict, group: str) -> Tuple[Optional[datetime.datetim
473
473
 
474
474
  if d is None and isExifTagUsable(data, f"{group}.GPSDateStamp"):
475
475
  try:
476
- dateRaw = data[f"{group}.GPSDateStamp"].replace(":", "-").replace("\x00", "")
476
+ dateRaw = data[f"{group}.GPSDateStamp"].replace(":", "-").replace("\x00", "").replace("/", "-")
477
477
 
478
478
  # Time
479
479
  if isExifTagUsable(data, f"{group}.GPSTimeStamp", List[Fraction]):
@@ -8,8 +8,8 @@ license = {file = "LICENSE"}
8
8
  classifiers = ["License :: OSI Approved :: MIT License"]
9
9
  dynamic = ["version", "description"]
10
10
  dependencies = [
11
- "typer ~= 0.9.0",
12
- "xmltodict ~= 0.13.0",
11
+ "typer ~= 0.12",
12
+ "xmltodict ~= 0.13",
13
13
  "pyexiv2 == 2.8.3",
14
14
  ]
15
15
  requires-python = ">=3.8"
@@ -22,14 +22,12 @@ geopic-tag-reader="geopic_tag_reader.main:app"
22
22
 
23
23
  [project.optional-dependencies]
24
24
  dev = [
25
- "black ~= 22.8.0",
26
- "mypy ~= 1.0.0",
25
+ "black ~= 24.3",
26
+ "mypy ~= 1.9",
27
27
  "pytest ~= 7.2.0",
28
- "pytest-datafiles ~= 2.0.1",
29
- "typer-cli-forked ~= 0.0.14", # fork dependency needed until https://github.com/tiangolo/typer-cli/pull/120 is merged.
30
- #"typer-cli ~= 0.0.13",
28
+ "pytest-datafiles ~= 3.0",
31
29
  "lazydocs ~= 0.4.8",
32
- "types-xmltodict ~= 0.13.0",
30
+ "types-xmltodict ~= 0.13",
33
31
  "pre-commit ~= 3.3.3",
34
32
  ]
35
33
  build = ["flit ~= 3.8.0"]
@@ -143,7 +143,7 @@ def test_readPictureMetadata_noHeading(datafiles):
143
143
 
144
144
  @pytest.mark.datafiles(os.path.join(FIXTURE_DIR, "img_Ricoh_Theta.jpg"))
145
145
  def test_readPictureMetadata_ricoh_theta(datafiles):
146
- for f in datafiles.listdir():
146
+ for f in datafiles.iterdir():
147
147
  result = reader.readPictureMetadata(openImg(str(f)))
148
148
  assertGeoPicTagsEquals(
149
149
  result,
@@ -162,7 +162,7 @@ def test_readPictureMetadata_ricoh_theta(datafiles):
162
162
 
163
163
  @pytest.mark.datafiles(os.path.join(FIXTURE_DIR, "img_V4MPack.jpg"))
164
164
  def test_readPictureMetadata_v4mpack(datafiles):
165
- for f in datafiles.listdir():
165
+ for f in datafiles.iterdir():
166
166
  result = reader.readPictureMetadata(openImg(str(f)))
167
167
  assertGeoPicTagsEquals(
168
168
  result,
@@ -540,6 +540,26 @@ def test_readPictureMetadata_ricoh_noproj(datafiles):
540
540
  )
541
541
 
542
542
 
543
+ @pytest.mark.datafiles(os.path.join(FIXTURE_DIR, "gopromax_flat.jpg"))
544
+ def test_readPictureMetadata_gopromax_flat(datafiles):
545
+ result = reader.readPictureMetadata(openImg(str(datafiles) + "/gopromax_flat.jpg"))
546
+
547
+ assertGeoPicTagsEquals(
548
+ result,
549
+ {
550
+ "lat": 47.22555109997222,
551
+ "lon": -1.5631604999722222,
552
+ "ts": 1708173992.0,
553
+ "heading": None,
554
+ "type": "flat",
555
+ "make": "GoPro",
556
+ "model": "Max",
557
+ "focal_length": 3,
558
+ "altitude": 78,
559
+ },
560
+ )
561
+
562
+
543
563
  @pytest.mark.datafiles(os.path.join(FIXTURE_DIR, "broken_makernotes.jpg"))
544
564
  def test_readPictureMetadata_broken_makernotes(datafiles):
545
565
  result = reader.readPictureMetadata(openImg(str(datafiles) + "/broken_makernotes.jpg"))
@@ -579,3 +599,27 @@ def test_readPictureMetadata_datetime_offset(datafiles):
579
599
  "altitude": 79,
580
600
  },
581
601
  )
602
+
603
+
604
+ @pytest.mark.datafiles(os.path.join(FIXTURE_DIR, "gps_date_slash.jpg"))
605
+ def test_readPictureMetadata_gps_date_slash(datafiles):
606
+ result = reader.readPictureMetadata(openImg(str(datafiles) + "/gps_date_slash.jpg"))
607
+
608
+ assertGeoPicTagsEquals(
609
+ result,
610
+ {
611
+ "lat": 43.42541569992266,
612
+ "lon": 1.3766216000638112,
613
+ "ts": 1686640500.0,
614
+ "heading": None,
615
+ "type": "flat",
616
+ "make": None,
617
+ "model": None,
618
+ "focal_length": None,
619
+ "altitude": None,
620
+ "tagreader_warnings": [
621
+ "GPSLatitudeRef not found, assuming GPSLatitudeRef is North",
622
+ "GPSLongitudeRef not found, assuming GPSLongitudeRef is East",
623
+ ],
624
+ },
625
+ )