1package fileop
2
3import (
4 "math"
5 "time"
6
7 "git.sr.ht/~gabrielgio/img/pkg/components/media"
8 "github.com/barasher/go-exiftool"
9)
10
11func ReadExif(path string) (*media.MediaEXIF, error) {
12 et, err := exiftool.NewExiftool()
13 if err != nil {
14 return nil, err
15 }
16 defer et.Close()
17
18 newExif := &media.MediaEXIF{}
19 fileInfo := et.ExtractMetadata(path)[0]
20
21 // Get description
22 description, err := fileInfo.GetString("ImageDescription")
23 if err == nil {
24 newExif.Description = &description
25 }
26
27 // Get camera model
28 model, err := fileInfo.GetString("Model")
29 if err == nil {
30 newExif.Camera = &model
31 }
32
33 // Get Camera make
34 make, err := fileInfo.GetString("Make")
35 if err == nil {
36 newExif.Maker = &make
37 }
38
39 // Get lens
40 lens, err := fileInfo.GetString("LensModel")
41 if err == nil {
42 newExif.Lens = &lens
43 }
44
45 //Get time of photo
46 createDateKeys := []string{
47 "CreationDate",
48 "DateTimeOriginal",
49 "CreateDate",
50 "TrackCreateDate",
51 "MediaCreateDate",
52 "FileCreateDate",
53 "ModifyDate",
54 "TrackModifyDate",
55 "MediaModifyDate",
56 "FileModifyDate",
57 }
58 for _, createDateKey := range createDateKeys {
59 date, err := fileInfo.GetString(createDateKey)
60 if err == nil {
61 layout := "2006:01:02 15:04:05"
62 dateTime, err := time.Parse(layout, date)
63 if err == nil {
64 newExif.DateShot = &dateTime
65 } else {
66 layoutWithOffset := "2006:01:02 15:04:05+02:00"
67 dateTime, err = time.Parse(layoutWithOffset, date)
68 if err == nil {
69 newExif.DateShot = &dateTime
70 }
71 }
72 break
73 }
74 }
75
76 // Get exposure time
77 exposureTime, err := fileInfo.GetFloat("ExposureTime")
78 if err == nil {
79 newExif.Exposure = &exposureTime
80 }
81
82 // Get aperture
83 aperture, err := fileInfo.GetFloat("Aperture")
84 if err == nil {
85 newExif.Aperture = &aperture
86 }
87
88 // Get ISO
89 iso, err := fileInfo.GetInt("ISO")
90 if err == nil {
91 newExif.Iso = &iso
92 }
93
94 // Get focal length
95 focalLen, err := fileInfo.GetFloat("FocalLength")
96 if err == nil {
97 newExif.FocalLength = &focalLen
98 }
99
100 // Get flash info
101 flash, err := fileInfo.GetInt("Flash")
102 if err == nil {
103 newExif.Flash = &flash
104 }
105
106 // Get orientation
107 orientation, err := fileInfo.GetInt("Orientation")
108 if err == nil {
109 newExif.Orientation = &orientation
110 }
111
112 // Get exposure program
113 expProgram, err := fileInfo.GetInt("ExposureProgram")
114 if err == nil {
115 newExif.ExposureProgram = &expProgram
116 }
117
118 // GPS coordinates - longitude
119 longitudeRaw, err := fileInfo.GetFloat("GPSLongitude")
120 if err == nil {
121 newExif.GPSLongitude = &longitudeRaw
122 }
123
124 // GPS coordinates - latitude
125 latitudeRaw, err := fileInfo.GetFloat("GPSLatitude")
126 if err == nil {
127 newExif.GPSLatitude = &latitudeRaw
128 }
129
130 sanitizeEXIF(newExif)
131
132 return newExif, nil
133}
134
135// isFloatReal returns true when the float value represents a real number
136// (different than +Inf, -Inf or NaN)
137func isFloatReal(v float64) bool {
138 if math.IsInf(v, 1) {
139 return false
140 } else if math.IsInf(v, -1) {
141 return false
142 } else if math.IsNaN(v) {
143 return false
144 }
145 return true
146}
147
148// sanitizeEXIF removes any EXIF float64 field that is not a real number (+Inf,
149// -Inf or Nan)
150func sanitizeEXIF(exif *media.MediaEXIF) {
151 if exif.Exposure != nil && !isFloatReal(*exif.Exposure) {
152 exif.Exposure = nil
153 }
154 if exif.Aperture != nil && !isFloatReal(*exif.Aperture) {
155 exif.Aperture = nil
156 }
157 if exif.FocalLength != nil && !isFloatReal(*exif.FocalLength) {
158 exif.FocalLength = nil
159 }
160 if (exif.GPSLatitude != nil && !isFloatReal(*exif.GPSLatitude)) ||
161 (exif.GPSLongitude != nil && !isFloatReal(*exif.GPSLongitude)) {
162 exif.GPSLatitude = nil
163 exif.GPSLongitude = nil
164 }
165}