add most useful exif data to metadata

This commit is contained in:
fredrsf 2020-08-04 12:24:15 +03:00
parent af781a34dd
commit 856fb7405c
5 changed files with 542 additions and 70 deletions

View File

@ -6,6 +6,75 @@ package bimg
*/
import "C"
const (
Make = "exif-ifd0-Make"
Model = "exif-ifd0-Model"
Orientation = "exif-ifd0-Orientation"
XResolution = "exif-ifd0-XResolution"
YResolution = "exif-ifd0-YResolution"
ResolutionUnit = "exif-ifd0-ResolutionUnit"
Software = "exif-ifd0-Software"
Datetime = "exif-ifd0-DateTime"
YCbCrPositioning = "exif-ifd0-YCbCrPositioning"
Compression = "exif-ifd1-Compression"
ExposureTime = "exif-ifd2-ExposureTime"
FNumber = "exif-ifd2-FNumber"
ExposureProgram = "exif-ifd2-ExposureProgram"
ISOSpeedRatings = "exif-ifd2-ISOSpeedRatings"
ExifVersion = "exif-ifd2-ExifVersion"
DateTimeOriginal = "exif-ifd2-DateTimeOriginal"
DateTimeDigitized = "exif-ifd2-DateTimeDigitized"
ComponentsConfiguration = "exif-ifd2-ComponentsConfiguration"
ShutterSpeedValue = "exif-ifd2-ShutterSpeedValue"
ApertureValue = "exif-ifd2-ApertureValue"
BrightnessValue = "exif-ifd2-BrightnessValue"
ExposureBiasValue = "exif-ifd2-ExposureBiasValue"
MeteringMode = "exif-ifd2-MeteringMode"
Flash = "exif-ifd2-Flash"
FocalLength = "exif-ifd2-FocalLength"
SubjectArea = "exif-ifd2-SubjectArea"
MakerNote = "exif-ifd2-MakerNote"
SubSecTimeOriginal = "exif-ifd2-SubSecTimeOriginal"
SubSecTimeDigitized = "exif-ifd2-SubSecTimeDigitized"
FlashPixVersion = "exif-ifd2-FlashpixVersion"
ColorSpace = "exif-ifd2-ColorSpace"
PixelXDimension = "exif-ifd2-PixelXDimension"
PixelYDimension = "exif-ifd2-PixelYDimension"
SensingMethod = "exif-ifd2-SensingMethod"
SceneType = "exif-ifd2-SceneType"
ExposureMode = "exif-ifd2-ExposureMode"
WhiteBalance = "exif-ifd2-WhiteBalance"
FocalLengthIn35mmFilm = "exif-ifd2-FocalLengthIn35mmFilm"
SceneCaptureType = "exif-ifd2-SceneCaptureType"
LensSpecification = "exif-ifd2-LensSpecification"
LensMake = "exif-ifd2-LensMake"
LensModel = "exif-ifd2-LensModel"
CompositeImage = "exif-ifd2-CompositeImage"
UserComment = "exif-ifd2-UserComment"
SubSecTime = "exif-ifd2-SubsecTime"
FocalPlaneXResolution = "exif-ifd2-FocalPlaneXResolution"
FocalPlaneYResolution = "exif-ifd2-FocalPlaneYResolution"
FocalPlaneResolutionUnit = "exif-ifd2-FocalPlaneResolutionUnit"
CustomRendered = "exif-ifd2-CustomRendered"
GPSLatitudeRef = "exif-ifd3-GPSLatitudeRef"
GPSLatitude = "exif-ifd3-GPSLatitude"
GPSLongitudeRef = "exif-ifd3-GPSLongitudeRef"
GPSLongitude = "exif-ifd3-GPSLongitude"
GPSAltitudeRef = "exif-ifd3-GPSAltitudeRef"
GPSAltitude = "exif-ifd3-GPSAltitude"
GPSSpeedRef = "exif-ifd3-GPSSpeedRef"
GPSSpeed = "exif-ifd3-GPSSpeed"
GPSImgDirectionRef = "exif-ifd3-GPSImgDirectionRef"
GPSImgDirection = "exif-ifd3-GPSImgDirection"
GPSDestBearingRef = "exif-ifd3-GPSDestBearingRef"
GPSDestBearing = "exif-ifd3-GPSDestBearing"
GPSDateStamp = "exif-ifd3-GPSDateStamp"
GPSHPositioningError = "exif-ifd3-GPSHPositioningError"
GPSVersionID = "exif-ifd3-GPSVersionID"
InteroperabilityIndex = "exif-ifd4-InteroperabilityIndex"
InteroperabilityVersion = "exif-ifd4-InteroperabilityVersion"
)
// ImageSize represents the image width and height values
type ImageSize struct {
Width int
@ -29,8 +98,69 @@ type EXIF struct {
Make string
Model string
Orientation int
XResolution string
YResolution string
ResolutionUnit int
Software string
Datetime string
YCbCrPositioning int
Compression int
ExposureTime string
FNumber string
ExposureProgram int
ISOSpeedRatings int
ExifVersion string
DateTimeOriginal string
DateTimeDigitized string
ComponentsConfiguration string
ShutterSpeedValue string
ApertureValue string
BrightnessValue string
ExposureBiasValue string
MeteringMode int
Flash int
FocalLength string
SubjectArea string
MakerNote string
SubSecTimeOriginal string
SubSecTimeDigitized string
FlashPixVersion string
ColorSpace int
PixelXDimension int
PixelYDimension int
SensingMethod int
SceneType string
ExposureMode int
WhiteBalance int
FocalLengthIn35mmFilm int
SceneCaptureType int
LensSpecification string
LensMake string
LensModel string
CompositeImage int
UserComment string
SubSecTime string
FocalPlaneXResolution string
FocalPlaneYResolution string
FocalPlaneResolutionUnit int
CustomRendered int
GPSLatitudeRef string
GPSLatitude string
GPSLongitudeRef string
GPSLongitude string
GPSAltitudeRef string
GPSAltitude string
GPSSpeedRef string
GPSSpeed string
GPSImgDirectionRef string
GPSImgDirection string
GPSDestBearingRef string
GPSDestBearing string
GPSDateStamp string
GPSHPositioningError string
GPSVersionID string
InteroperabilityIndex string
InteroperabilityVersion string
}
// Size returns the image size by width and height pixels.
@ -72,7 +202,7 @@ func Metadata(buf []byte) (ImageMetadata, error) {
Height: int(image.Ysize),
}
orientation := vipsExifOrientation(image)
orientation := vipsExifIntTag(image, Orientation)
metadata := ImageMetadata{
Size: size,
@ -83,11 +213,72 @@ func Metadata(buf []byte) (ImageMetadata, error) {
Space: vipsSpace(image),
Type: ImageTypeName(imageType),
EXIF: EXIF{
Make: vipsExifMake(image),
Model: vipsExifModel(image),
Make: vipsExifStringTag(image, Make),
Model: vipsExifStringTag(image, Model),
Orientation: orientation,
Software: vipsExifSoftware(image),
Datetime: vipsExifDatetime(image),
XResolution: vipsExifStringTag(image, XResolution),
YResolution: vipsExifStringTag(image, YResolution),
ResolutionUnit: vipsExifIntTag(image, ResolutionUnit),
Software: vipsExifStringTag(image, Software),
Datetime: vipsExifStringTag(image, Datetime),
YCbCrPositioning: vipsExifIntTag(image, YCbCrPositioning),
Compression: vipsExifIntTag(image, Compression),
ExposureTime: vipsExifStringTag(image, ExposureTime),
FNumber: vipsExifStringTag(image, FNumber),
ExposureProgram: vipsExifIntTag(image, ExposureProgram),
ISOSpeedRatings: vipsExifIntTag(image, ISOSpeedRatings),
ExifVersion: vipsExifStringTag(image, ExifVersion),
DateTimeOriginal: vipsExifStringTag(image, DateTimeOriginal),
DateTimeDigitized: vipsExifStringTag(image, DateTimeDigitized),
ComponentsConfiguration: vipsExifStringTag(image, ComponentsConfiguration),
ShutterSpeedValue: vipsExifStringTag(image, ShutterSpeedValue),
ApertureValue: vipsExifStringTag(image, ApertureValue),
BrightnessValue: vipsExifStringTag(image, BrightnessValue),
ExposureBiasValue: vipsExifStringTag(image, ExposureBiasValue),
MeteringMode: vipsExifIntTag(image, MeteringMode),
Flash: vipsExifIntTag(image, Flash),
FocalLength: vipsExifStringTag(image, FocalLength),
SubjectArea: vipsExifStringTag(image, SubjectArea),
MakerNote: vipsExifStringTag(image, MakerNote),
SubSecTimeOriginal: vipsExifStringTag(image, SubSecTimeOriginal),
SubSecTimeDigitized: vipsExifStringTag(image, SubSecTimeDigitized),
FlashPixVersion: vipsExifStringTag(image, FlashPixVersion),
ColorSpace: vipsExifIntTag(image, ColorSpace),
PixelXDimension: vipsExifIntTag(image, PixelXDimension),
PixelYDimension: vipsExifIntTag(image, PixelYDimension),
SensingMethod: vipsExifIntTag(image, SensingMethod),
SceneType: vipsExifStringTag(image, SceneType),
ExposureMode: vipsExifIntTag(image, ExposureMode),
WhiteBalance: vipsExifIntTag(image, WhiteBalance),
FocalLengthIn35mmFilm: vipsExifIntTag(image, FocalLengthIn35mmFilm),
SceneCaptureType: vipsExifIntTag(image, SceneCaptureType),
LensSpecification: vipsExifStringTag(image, LensSpecification),
LensMake: vipsExifStringTag(image, LensMake),
LensModel: vipsExifStringTag(image, LensModel),
CompositeImage: vipsExifIntTag(image, CompositeImage),
UserComment: vipsExifStringTag(image, UserComment),
SubSecTime: vipsExifStringTag(image, SubSecTime),
FocalPlaneXResolution: vipsExifStringTag(image, FocalPlaneXResolution),
FocalPlaneYResolution: vipsExifStringTag(image, FocalPlaneYResolution),
FocalPlaneResolutionUnit: vipsExifIntTag(image, FocalPlaneResolutionUnit),
CustomRendered: vipsExifIntTag(image, CustomRendered),
GPSLatitudeRef: vipsExifStringTag(image, GPSLatitudeRef),
GPSLatitude: vipsExifStringTag(image, GPSLatitude),
GPSLongitudeRef: vipsExifStringTag(image, GPSLongitudeRef),
GPSLongitude: vipsExifStringTag(image, GPSLongitude),
GPSAltitudeRef: vipsExifStringTag(image, GPSAltitudeRef),
GPSAltitude: vipsExifStringTag(image, GPSAltitude),
GPSSpeedRef: vipsExifStringTag(image, GPSSpeedRef),
GPSSpeed: vipsExifStringTag(image, GPSSpeed),
GPSImgDirectionRef: vipsExifStringTag(image, GPSImgDirectionRef),
GPSImgDirection: vipsExifStringTag(image, GPSImgDirection),
GPSDestBearingRef: vipsExifStringTag(image, GPSDestBearingRef),
GPSDestBearing: vipsExifStringTag(image, GPSDestBearing),
GPSDateStamp: vipsExifStringTag(image, GPSDateStamp),
GPSHPositioningError: vipsExifStringTag(image, GPSHPositioningError),
GPSVersionID: vipsExifStringTag(image, GPSVersionID),
InteroperabilityIndex: vipsExifStringTag(image, InteroperabilityIndex),
InteroperabilityVersion: vipsExifStringTag(image, InteroperabilityVersion),
},
}

View File

@ -90,39 +90,347 @@ func TestImageInterpretation(t *testing.T) {
}
func TestEXIF(t *testing.T) {
files := []struct {
name string
make string
model string
orientation int
software string
datetime string
}{
{"test.jpg", "", "", 0, "", ""},
{"exif/Landscape_1.jpg", "", "", 1, "", ""},
{"test_exif.jpg", "Jolla", "Jolla", 1, "", "2014:09:21 16:00:56"},
{"test_exif_canon.jpg", "Canon", "Canon EOS 40D", 1, "GIMP 2.4.5", "2008:07:31 10:38:11"},
files := map[string]EXIF {
"test.jpg": {},
"exif/Landscape_1.jpg": {
Orientation: 1,
XResolution: "72/1",
YResolution: "72/1",
ResolutionUnit: 2,
YCbCrPositioning: 1,
ExifVersion: "Exif Version 2.1",
FlashPixVersion: "FlashPix Version 1.0",
ColorSpace: 65535,
},
"test_exif.jpg": {
Make: "Jolla",
Model: "Jolla",
XResolution: "25400/1000",
YResolution: "25400/1000",
ResolutionUnit: 2,
Orientation: 1,
Datetime: "2014:09:21 16:00:56",
ExposureTime: "1/25",
FNumber: "12/5",
ISOSpeedRatings: 320,
ExifVersion: "Exif Version 2.3",
DateTimeOriginal: "2014:09:21 16:00:56",
ShutterSpeedValue: "205447286/44240665",
ApertureValue: "334328577/132351334",
ExposureBiasValue: "0/1",
MeteringMode: 1,
Flash: 0,
FocalLength: "4/1",
FlashPixVersion: "FlashPix Version 1.0",
WhiteBalance: 1,
ColorSpace: 65535,
},
"test_exif_canon.jpg": {
Make: "Canon",
Model: "Canon EOS 40D",
Orientation: 1,
XResolution: "72/1",
YResolution: "72/1",
ResolutionUnit: 2,
Software: "GIMP 2.4.5",
Datetime: "2008:07:31 10:38:11",
YCbCrPositioning: 2,
Compression: 6,
ExposureTime: "1/160",
FNumber: "71/10",
ExposureProgram: 1,
ISOSpeedRatings: 100,
ExifVersion: "Exif Version 2.21",
DateTimeOriginal: "2008:05:30 15:56:01",
DateTimeDigitized: "2008:05:30 15:56:01",
ComponentsConfiguration: "Y Cb Cr -",
ShutterSpeedValue: "483328/65536",
ApertureValue: "368640/65536",
ExposureBiasValue: "0/1",
MeteringMode: 5,
Flash: 9,
FocalLength: "135/1",
SubSecTime: "00",
SubSecTimeOriginal: "00",
SubSecTimeDigitized: "00",
FlashPixVersion: "FlashPix Version 1.0",
ColorSpace: 1,
PixelXDimension: 100,
PixelYDimension: 68,
FocalPlaneXResolution: "3888000/876",
FocalPlaneYResolution: "2592000/583",
FocalPlaneResolutionUnit: 2,
CustomRendered: 0,
ExposureMode: 1,
WhiteBalance: 0,
SceneCaptureType: 0,
GPSVersionID: "2.2.0.0",
InteroperabilityIndex: "R98",
InteroperabilityVersion: "0100",
},
"test_exif_full.jpg": {
Make: "Apple",
Model: "iPhone XS",
Orientation: 6,
XResolution: "72/1",
YResolution: "72/1",
ResolutionUnit: 2,
Software: "13.3.1",
Datetime: "2020:07:28 19:18:49",
YCbCrPositioning: 1,
Compression: 6,
ExposureTime: "1/835",
FNumber: "9/5",
ExposureProgram: 2,
ISOSpeedRatings: 25,
ExifVersion: "Unknown Exif Version",
DateTimeOriginal: "2020:07:28 19:18:49",
DateTimeDigitized: "2020:07:28 19:18:49",
ComponentsConfiguration: "Y Cb Cr -",
ShutterSpeedValue: "77515/7986",
ApertureValue: "54823/32325",
BrightnessValue: "77160/8623",
ExposureBiasValue: "0/1",
MeteringMode: 5,
Flash: 16,
FocalLength: "17/4",
SubjectArea: "2013 1511 2217 1330",
MakerNote: "1110 bytes undefined data",
SubSecTimeOriginal: "777",
SubSecTimeDigitized: "777",
FlashPixVersion: "FlashPix Version 1.0",
ColorSpace: 65535,
PixelXDimension: 4032,
PixelYDimension: 3024,
SensingMethod: 2,
SceneType: "Directly photographed",
ExposureMode: 0,
WhiteBalance: 0,
FocalLengthIn35mmFilm: 26,
SceneCaptureType: 0,
LensSpecification: "17/4 6/1 9/5 12/5",
LensMake: "Apple",
LensModel: "iPhone XS back dual camera 4.25mm f/1.8",
CompositeImage: 2,
GPSLatitudeRef: "N",
GPSLatitude: "55/1 43/1 5287/100",
GPSLongitudeRef: "E",
GPSLongitude: "37/1 35/1 5571/100",
GPSAltitudeRef: "Sea level",
GPSAltitude: "90514/693",
GPSSpeedRef: "K",
GPSSpeed: "114272/41081",
GPSImgDirectionRef: "M",
GPSImgDirection: "192127/921",
GPSDestBearingRef: "M",
GPSDestBearing: "192127/921",
GPSDateStamp: "2020:07:28",
GPSHPositioningError: "99327/19144",
},
}
for _, file := range files {
metadata, err := Metadata(readFile(file.name))
for name, file := range files {
metadata, err := Metadata(readFile(name))
if err != nil {
t.Fatalf("Cannot read the image: %s -> %s", file.name, err)
t.Fatalf("Cannot read the image: %s -> %s", name, err)
}
if metadata.EXIF.Make != file.make {
t.Fatalf("Unexpected image exif make: %s != %s", metadata.EXIF.Make, file.make)
if metadata.EXIF.Make != file.Make {
t.Fatalf("Unexpected image exif Make: %s != %s", metadata.EXIF.Make, file.Make)
}
if metadata.EXIF.Model != file.model {
t.Fatalf("Unexpected image exif model: %s != %s", metadata.EXIF.Model, file.model)
if metadata.EXIF.Model != file.Model {
t.Fatalf("Unexpected image exif Model: %s != %s", metadata.EXIF.Model, file.Model)
}
if metadata.EXIF.Orientation != file.orientation {
t.Fatalf("Unexpected image exif orientation: %d != %d", metadata.EXIF.Orientation, file.orientation)
if metadata.EXIF.Orientation != file.Orientation {
t.Fatalf("Unexpected image exif Orientation: %d != %d", metadata.EXIF.Orientation, file.Orientation)
}
if metadata.EXIF.Software != file.software {
t.Fatalf("Unexpected image exif software: %s != %s", metadata.EXIF.Software, file.software)
if metadata.EXIF.XResolution != file.XResolution {
t.Fatalf("Unexpected image exif XResolution: %s != %s", metadata.EXIF.XResolution, file.XResolution)
}
if metadata.EXIF.Datetime != file.datetime {
t.Fatalf("Unexpected image exif datetime: %s != %s", metadata.EXIF.Datetime, file.datetime)
if metadata.EXIF.YResolution != file.YResolution {
t.Fatalf("Unexpected image exif YResolution: %s != %s", metadata.EXIF.YResolution, file.YResolution)
}
if metadata.EXIF.ResolutionUnit != file.ResolutionUnit {
t.Fatalf("Unexpected image exif ResolutionUnit: %d != %d", metadata.EXIF.ResolutionUnit, file.ResolutionUnit)
}
if metadata.EXIF.Software != file.Software {
t.Fatalf("Unexpected image exif Software: %s != %s", metadata.EXIF.Software, file.Software)
}
if metadata.EXIF.Datetime != file.Datetime {
t.Fatalf("Unexpected image exif Datetime: %s != %s", metadata.EXIF.Datetime, file.Datetime)
}
if metadata.EXIF.YCbCrPositioning != file.YCbCrPositioning {
t.Fatalf("Unexpected image exif YCbCrPositioning: %d != %d", metadata.EXIF.YCbCrPositioning, file.YCbCrPositioning)
}
if metadata.EXIF.Compression != file.Compression {
t.Fatalf("Unexpected image exif Compression: %d != %d", metadata.EXIF.Compression, file.Compression)
}
if metadata.EXIF.ExposureTime != file.ExposureTime {
t.Fatalf("Unexpected image exif ExposureTime: %s != %s", metadata.EXIF.ExposureTime, file.ExposureTime)
}
if metadata.EXIF.FNumber != file.FNumber {
t.Fatalf("Unexpected image exif FNumber: %s != %s", metadata.EXIF.FNumber, file.FNumber)
}
if metadata.EXIF.ExposureProgram != file.ExposureProgram {
t.Fatalf("Unexpected image exif ExposureProgram: %d != %d", metadata.EXIF.ExposureProgram, file.ExposureProgram)
}
if metadata.EXIF.ISOSpeedRatings != file.ISOSpeedRatings {
t.Fatalf("Unexpected image exif ISOSpeedRatings: %d != %d", metadata.EXIF.ISOSpeedRatings, file.ISOSpeedRatings)
}
if metadata.EXIF.ExifVersion != file.ExifVersion {
t.Fatalf("Unexpected image exif ExifVersion: %s != %s", metadata.EXIF.ExifVersion, file.ExifVersion)
}
if metadata.EXIF.DateTimeOriginal != file.DateTimeOriginal {
t.Fatalf("Unexpected image exif DateTimeOriginal: %s != %s", metadata.EXIF.DateTimeOriginal, file.DateTimeOriginal)
}
if metadata.EXIF.DateTimeDigitized != file.DateTimeDigitized {
t.Fatalf("Unexpected image exif DateTimeDigitized: %s != %s", metadata.EXIF.DateTimeDigitized, file.DateTimeDigitized)
}
if metadata.EXIF.ComponentsConfiguration != file.ComponentsConfiguration {
t.Fatalf("Unexpected image exif ComponentsConfiguration: %s != %s", metadata.EXIF.ComponentsConfiguration, file.ComponentsConfiguration)
}
if metadata.EXIF.ShutterSpeedValue != file.ShutterSpeedValue {
t.Fatalf("Unexpected image exif ShutterSpeedValue: %s != %s", metadata.EXIF.ShutterSpeedValue, file.ShutterSpeedValue)
}
if metadata.EXIF.ApertureValue != file.ApertureValue {
t.Fatalf("Unexpected image exif ApertureValue: %s != %s", metadata.EXIF.ApertureValue, file.ApertureValue)
}
if metadata.EXIF.BrightnessValue != file.BrightnessValue {
t.Fatalf("Unexpected image exif BrightnessValue: %s != %s", metadata.EXIF.BrightnessValue, file.BrightnessValue)
}
if metadata.EXIF.ExposureBiasValue != file.ExposureBiasValue {
t.Fatalf("Unexpected image exif ExposureBiasValue: %s != %s", metadata.EXIF.ExposureBiasValue, file.ExposureBiasValue)
}
if metadata.EXIF.MeteringMode != file.MeteringMode {
t.Fatalf("Unexpected image exif MeteringMode: %d != %d", metadata.EXIF.MeteringMode, file.MeteringMode)
}
if metadata.EXIF.Flash != file.Flash {
t.Fatalf("Unexpected image exif Flash: %d != %d", metadata.EXIF.Flash, file.Flash)
}
if metadata.EXIF.FocalLength != file.FocalLength {
t.Fatalf("Unexpected image exif FocalLength: %s != %s", metadata.EXIF.FocalLength, file.FocalLength)
}
if metadata.EXIF.SubjectArea != file.SubjectArea {
t.Fatalf("Unexpected image exif SubjectArea: %s != %s", metadata.EXIF.SubjectArea, file.SubjectArea)
}
if metadata.EXIF.MakerNote != file.MakerNote {
t.Fatalf("Unexpected image exif MakerNote: %s != %s", metadata.EXIF.MakerNote, file.MakerNote)
}
if metadata.EXIF.SubSecTimeOriginal != file.SubSecTimeOriginal {
t.Fatalf("Unexpected image exif SubSecTimeOriginal: %s != %s", metadata.EXIF.SubSecTimeOriginal, file.SubSecTimeOriginal)
}
if metadata.EXIF.SubSecTimeDigitized != file.SubSecTimeDigitized {
t.Fatalf("Unexpected image exif SubSecTimeDigitized: %s != %s", metadata.EXIF.SubSecTimeDigitized, file.SubSecTimeDigitized)
}
if metadata.EXIF.FlashPixVersion != file.FlashPixVersion {
t.Fatalf("Unexpected image exif FlashPixVersion: %s != %s", metadata.EXIF.FlashPixVersion, file.FlashPixVersion)
}
if metadata.EXIF.ColorSpace != file.ColorSpace {
t.Fatalf("Unexpected image exif ColorSpace: %d != %d", metadata.EXIF.ColorSpace, file.ColorSpace)
}
if metadata.EXIF.PixelXDimension != file.PixelXDimension {
t.Fatalf("Unexpected image exif PixelXDimension: %d != %d", metadata.EXIF.PixelXDimension, file.PixelXDimension)
}
if metadata.EXIF.PixelYDimension != file.PixelYDimension {
t.Fatalf("Unexpected image exif PixelYDimension: %d != %d", metadata.EXIF.PixelYDimension, file.PixelYDimension)
}
if metadata.EXIF.SensingMethod != file.SensingMethod {
t.Fatalf("Unexpected image exif SensingMethod: %d != %d", metadata.EXIF.SensingMethod, file.SensingMethod)
}
if metadata.EXIF.SceneType != file.SceneType {
t.Fatalf("Unexpected image exif SceneType: %s != %s", metadata.EXIF.SceneType, file.SceneType)
}
if metadata.EXIF.ExposureMode != file.ExposureMode {
t.Fatalf("Unexpected image exif ExposureMode: %d != %d", metadata.EXIF.ExposureMode, file.ExposureMode)
}
if metadata.EXIF.WhiteBalance != file.WhiteBalance {
t.Fatalf("Unexpected image exif WhiteBalance: %d != %d", metadata.EXIF.WhiteBalance, file.WhiteBalance)
}
if metadata.EXIF.FocalLengthIn35mmFilm != file.FocalLengthIn35mmFilm {
t.Fatalf("Unexpected image exif FocalLengthIn35mmFilm: %d != %d", metadata.EXIF.FocalLengthIn35mmFilm, file.FocalLengthIn35mmFilm)
}
if metadata.EXIF.SceneCaptureType != file.SceneCaptureType {
t.Fatalf("Unexpected image exif SceneCaptureType: %d != %d", metadata.EXIF.SceneCaptureType, file.SceneCaptureType)
}
if metadata.EXIF.LensSpecification != file.LensSpecification {
t.Fatalf("Unexpected image exif LensSpecification: %s != %s", metadata.EXIF.LensSpecification, file.LensSpecification)
}
if metadata.EXIF.LensMake != file.LensMake {
t.Fatalf("Unexpected image exif LensMake: %s != %s", metadata.EXIF.LensMake, file.LensMake)
}
if metadata.EXIF.LensModel != file.LensModel {
t.Fatalf("Unexpected image exif LensModel: %s != %s", metadata.EXIF.LensModel, file.LensModel)
}
if metadata.EXIF.CompositeImage != file.CompositeImage {
t.Fatalf("Unexpected image exif CompositeImage: %d != %d", metadata.EXIF.CompositeImage, file.CompositeImage)
}
if metadata.EXIF.UserComment != file.UserComment {
t.Fatalf("Unexpected image exif UserComment: %s != %s", metadata.EXIF.UserComment, file.UserComment)
}
if metadata.EXIF.SubSecTime != file.SubSecTime {
t.Fatalf("Unexpected image exif SubSecTime: %s != %s", metadata.EXIF.SubSecTime, file.SubSecTime)
}
if metadata.EXIF.FocalPlaneXResolution != file.FocalPlaneXResolution {
t.Fatalf("Unexpected image exif FocalPlaneXResolution: %s != %s", metadata.EXIF.FocalPlaneXResolution, file.FocalPlaneXResolution)
}
if metadata.EXIF.FocalPlaneYResolution != file.FocalPlaneYResolution {
t.Fatalf("Unexpected image exif FocalPlaneYResolution: %s != %s", metadata.EXIF.FocalPlaneYResolution, file.FocalPlaneYResolution)
}
if metadata.EXIF.FocalPlaneResolutionUnit != file.FocalPlaneResolutionUnit {
t.Fatalf("Unexpected image exif FocalPlaneResolutionUnit: %d != %d", metadata.EXIF.FocalPlaneResolutionUnit, file.FocalPlaneResolutionUnit)
}
if metadata.EXIF.CustomRendered != file.CustomRendered {
t.Fatalf("Unexpected image exif CustomRendered: %d != %d", metadata.EXIF.CustomRendered, file.CustomRendered)
}
if metadata.EXIF.GPSLatitudeRef != file.GPSLatitudeRef {
t.Fatalf("Unexpected image exif GPSLatitudeRef: %s != %s", metadata.EXIF.GPSLatitudeRef, file.GPSLatitudeRef)
}
if metadata.EXIF.GPSLatitude != file.GPSLatitude {
t.Fatalf("Unexpected image exif GPSLatitude: %s != %s", metadata.EXIF.GPSLatitude, file.GPSLatitude)
}
if metadata.EXIF.GPSLongitudeRef != file.GPSLongitudeRef {
t.Fatalf("Unexpected image exif GPSLongitudeRef: %s != %s", metadata.EXIF.GPSLongitudeRef, file.GPSLongitudeRef)
}
if metadata.EXIF.GPSLongitude != file.GPSLongitude {
t.Fatalf("Unexpected image exif GPSLongitude: %s != %s", metadata.EXIF.GPSLongitude, file.GPSLongitude)
}
if metadata.EXIF.GPSAltitudeRef != file.GPSAltitudeRef {
t.Fatalf("Unexpected image exif GPSAltitudeRef: %s != %s", metadata.EXIF.GPSAltitudeRef, file.GPSAltitudeRef)
}
if metadata.EXIF.GPSAltitude != file.GPSAltitude {
t.Fatalf("Unexpected image exif GPSAltitude: %s != %s", metadata.EXIF.GPSAltitude, file.GPSAltitude)
}
if metadata.EXIF.GPSSpeedRef != file.GPSSpeedRef {
t.Fatalf("Unexpected image exif GPSSpeedRef: %s != %s", metadata.EXIF.GPSSpeedRef, file.GPSSpeedRef)
}
if metadata.EXIF.GPSSpeed != file.GPSSpeed {
t.Fatalf("Unexpected image exif GPSSpeed: %s != %s", metadata.EXIF.GPSSpeed, file.GPSSpeed)
}
if metadata.EXIF.GPSImgDirectionRef != file.GPSImgDirectionRef {
t.Fatalf("Unexpected image exif GPSImgDirectionRef: %s != %s", metadata.EXIF.GPSImgDirectionRef, file.GPSImgDirectionRef)
}
if metadata.EXIF.GPSImgDirection != file.GPSImgDirection {
t.Fatalf("Unexpected image exif GPSImgDirection: %s != %s", metadata.EXIF.GPSImgDirection, file.GPSImgDirection)
}
if metadata.EXIF.GPSDestBearingRef != file.GPSDestBearingRef {
t.Fatalf("Unexpected image exif GPSDestBearingRef: %s != %s", metadata.EXIF.GPSDestBearingRef, file.GPSDestBearingRef)
}
if metadata.EXIF.GPSDestBearing != file.GPSDestBearing {
t.Fatalf("Unexpected image exif GPSDestBearing: %s != %s", metadata.EXIF.GPSDestBearing, file.GPSDestBearing)
}
if metadata.EXIF.GPSDateStamp != file.GPSDateStamp {
t.Fatalf("Unexpected image exif GPSDateStamp: %s != %s", metadata.EXIF.GPSDateStamp, file.GPSDateStamp)
}
if metadata.EXIF.GPSHPositioningError != file.GPSHPositioningError {
t.Fatalf("Unexpected image exif GPSHPositioningError: %s != %s", metadata.EXIF.GPSHPositioningError, file.GPSHPositioningError)
}
if metadata.EXIF.GPSVersionID != file.GPSVersionID {
t.Fatalf("Unexpected image exif GPSVersionID: %s != %s", metadata.EXIF.GPSVersionID, file.GPSVersionID)
}
if metadata.EXIF.InteroperabilityIndex != file.InteroperabilityIndex {
t.Fatalf("Unexpected image exif InteroperabilityIndex: %s != %s", metadata.EXIF.InteroperabilityIndex, file.InteroperabilityIndex)
}
if metadata.EXIF.InteroperabilityVersion != file.InteroperabilityVersion {
t.Fatalf("Unexpected image exif InteroperabilityVersion: %s != %s", metadata.EXIF.InteroperabilityVersion, file.InteroperabilityVersion)
}
}
}

BIN
testdata/test_exif_full.jpg vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 MiB

16
vips.go
View File

@ -215,26 +215,18 @@ func VipsIsTypeSupportedSave(t ImageType) bool {
return false
}
func vipsExifMake(image *C.VipsImage) string {
return vipsExifShort(C.GoString(C.vips_exif_make(image)))
func vipsExifStringTag(image *C.VipsImage, tag string) string {
return vipsExifShort(C.GoString(C.vips_exif_tag(image, C.CString(tag))))
}
func vipsExifModel(image *C.VipsImage) string {
return vipsExifShort(C.GoString(C.vips_exif_model(image)))
func vipsExifIntTag(image *C.VipsImage, tag string) int {
return int(C.vips_exif_tag_to_int(image, C.CString(tag)))
}
func vipsExifOrientation(image *C.VipsImage) int {
return int(C.vips_exif_orientation(image))
}
func vipsExifSoftware(image *C.VipsImage) string {
return vipsExifShort(C.GoString(C.vips_exif_software(image)))
}
func vipsExifDatetime(image *C.VipsImage) string {
return vipsExifShort(C.GoString(C.vips_exif_datetime(image)))
}
func vipsExifShort(s string) string {
if strings.Contains(s, " (") {
return s[:strings.Index(s, "(")-1]

37
vips.h
View File

@ -18,11 +18,7 @@
#define VIPS_ANGLE_D270 VIPS_ANGLE_270
#endif
#define EXIF_IFD0_MAKE "exif-ifd0-Make"
#define EXIF_IFD0_MODEL "exif-ifd0-Model"
#define EXIF_IFD0_ORIENTATION "exif-ifd0-Orientation"
#define EXIF_IFD0_SOFTWARE "exif-ifd0-Software"
#define EXIF_IFD0_DATETIME "exif-ifd0-DateTime"
#define INT_TO_GBOOLEAN(bool) (bool > 0 ? TRUE : FALSE)
@ -234,34 +230,19 @@ vips_exif_tag(VipsImage *image, const char *tag) {
return "";
}
const char *
vips_exif_make(VipsImage *image) {
return vips_exif_tag(image, EXIF_IFD0_MAKE);
}
const char *
vips_exif_model(VipsImage *image) {
return vips_exif_tag(image, EXIF_IFD0_MODEL);
int
vips_exif_tag_to_int(VipsImage *image, const char *tag) {
int value = 0;
const char *exif = vips_exif_tag(image, tag);
if (strcmp(exif, "")) {
value = atoi(&exif[0]);
}
return value;
}
int
vips_exif_orientation(VipsImage *image) {
int orientation = 0;
const char *exif = vips_exif_tag(image, EXIF_IFD0_ORIENTATION);
if (strcmp(exif, "")) {
orientation = atoi(&exif[0]);
}
return orientation;
}
const char *
vips_exif_software(VipsImage *image) {
return vips_exif_tag(image, EXIF_IFD0_SOFTWARE);
}
const char *
vips_exif_datetime(VipsImage *image) {
return vips_exif_tag(image, EXIF_IFD0_DATETIME);
return vips_exif_tag_to_int(image, EXIF_IFD0_ORIENTATION);
}
int