精简后的项目:仅保留 api/ui 源码、文档、构建依赖
This commit is contained in:
@@ -0,0 +1,171 @@
|
||||
package exiftool
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// GPS stores gps-related tags.
|
||||
type GPS struct {
|
||||
GPSLatitude *float64
|
||||
GPSLongitude *float64
|
||||
}
|
||||
|
||||
// IsValid returns true when GPS data is valid.
|
||||
func (gps GPS) IsValid() bool {
|
||||
if gps.GPSLongitude == nil || gps.GPSLatitude == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
if math.IsNaN(*gps.GPSLatitude) {
|
||||
return false
|
||||
}
|
||||
|
||||
if math.IsNaN(*gps.GPSLongitude) {
|
||||
return false
|
||||
}
|
||||
|
||||
if math.Abs(*gps.GPSLatitude) > 90 || math.Abs(*gps.GPSLongitude) > 180 {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func (gps GPS) String() string {
|
||||
if !gps.IsValid() {
|
||||
return "GPS(invalid)"
|
||||
}
|
||||
|
||||
return fmt.Sprintf("GPS(%.9f, %.9f)", *gps.GPSLatitude, *gps.GPSLongitude)
|
||||
}
|
||||
|
||||
// TimeAll stores tags returned by -time:all.
|
||||
type TimeAll struct {
|
||||
SubSecDateTimeOriginal *string
|
||||
SubSecCreateDate *string
|
||||
|
||||
DateTimeOriginal *string
|
||||
CreateDate *string
|
||||
TrackCreateDate *string
|
||||
MediaCreateDate *string
|
||||
FileModifyDate *string
|
||||
|
||||
OffsetTimeOriginal *string
|
||||
OffsetTime *string
|
||||
TimeZone *int
|
||||
|
||||
GPSDateTime *string
|
||||
}
|
||||
|
||||
const layout = "2006:01:02 15:04:05.999"
|
||||
const layoutWithTimezone = "2006:01:02 15:04:05.999Z07:00"
|
||||
|
||||
// TimeInLocal returns most likely time. The date and time are in local. The timezone is meaningless and always be in UTC. Use `OffsetSecs()` to determine the timezone.
|
||||
func (t TimeAll) TimeInLocal() time.Time {
|
||||
for _, dateP := range []*string{
|
||||
// Keep the order for the priority to generate DateShot
|
||||
t.SubSecDateTimeOriginal,
|
||||
t.SubSecCreateDate,
|
||||
t.DateTimeOriginal,
|
||||
t.CreateDate,
|
||||
t.TrackCreateDate,
|
||||
t.MediaCreateDate,
|
||||
t.FileModifyDate,
|
||||
} {
|
||||
if dateP == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
date := *dateP
|
||||
|
||||
// Ignore timezone
|
||||
if zoneIndex := strings.IndexAny(date, "+-Z"); zoneIndex >= 0 {
|
||||
date = date[:zoneIndex]
|
||||
}
|
||||
|
||||
if date, err := time.ParseInLocation(layout, date, time.UTC); err == nil {
|
||||
return date
|
||||
}
|
||||
}
|
||||
|
||||
return time.Time{}
|
||||
}
|
||||
|
||||
// OffsetSecs returns seconds offset by UTC.
|
||||
func (t TimeAll) OffsetSecs(local time.Time) (int, bool) {
|
||||
for _, offsetP := range []*string{
|
||||
t.OffsetTimeOriginal,
|
||||
t.OffsetTime,
|
||||
} {
|
||||
if offsetP == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if t, err := time.Parse("-07:00", *offsetP); err == nil {
|
||||
_, offsetSecs := t.Zone()
|
||||
return offsetSecs, true
|
||||
}
|
||||
}
|
||||
|
||||
// TimeZone is in minutes
|
||||
if t.TimeZone != nil {
|
||||
return *t.TimeZone * 60, true
|
||||
}
|
||||
|
||||
// Calculate offset sec with GPS time and local time.
|
||||
if local.IsZero() {
|
||||
return 0, false
|
||||
}
|
||||
|
||||
if t.GPSDateTime == nil {
|
||||
return 0, false
|
||||
}
|
||||
|
||||
gpsDate, err := time.Parse(layoutWithTimezone, *t.GPSDateTime)
|
||||
if err != nil {
|
||||
return 0, false
|
||||
}
|
||||
gpsDate = gpsDate.UTC()
|
||||
|
||||
// GPS time is always UTC per EXIF spec
|
||||
// offset = local time (in UTC) - GPS UTC time
|
||||
offset := int(local.Sub(gpsDate).Seconds())
|
||||
return offset, true
|
||||
}
|
||||
|
||||
type PhotoMeta struct {
|
||||
ImageDescription *string
|
||||
Model *string
|
||||
Make *string
|
||||
LensModel *string
|
||||
ISO *int64
|
||||
Flash *int64
|
||||
Orientation *int64
|
||||
ExposureProgram *int64
|
||||
ExposureTime *float64
|
||||
Aperture *float64
|
||||
FocalLength *float64
|
||||
}
|
||||
|
||||
func (m *PhotoMeta) SanitizeFloats() {
|
||||
for _, value := range []**float64{
|
||||
&m.ExposureTime,
|
||||
&m.Aperture,
|
||||
&m.FocalLength,
|
||||
} {
|
||||
if *value == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if math.IsNaN(**value) || math.IsInf(**value, 0) {
|
||||
*value = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type MIMEType struct {
|
||||
MIMEType *string
|
||||
}
|
||||
Reference in New Issue
Block a user