diff --git a/metadata.go b/metadata.go index 8e5e9ae..2f6f730 100644 --- a/metadata.go +++ b/metadata.go @@ -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), }, } diff --git a/metadata_test.go b/metadata_test.go index 00ca244..008e288 100644 --- a/metadata_test.go +++ b/metadata_test.go @@ -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.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.XResolution != file.XResolution { + t.Fatalf("Unexpected image exif XResolution: %s != %s", metadata.EXIF.XResolution, file.XResolution) + } + 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.Make != file.make { - t.Fatalf("Unexpected image exif make: %s != %s", metadata.EXIF.Make, file.make) + if metadata.EXIF.GPSDateStamp != file.GPSDateStamp { + t.Fatalf("Unexpected image exif GPSDateStamp: %s != %s", metadata.EXIF.GPSDateStamp, file.GPSDateStamp) } - if metadata.EXIF.Model != file.model { - t.Fatalf("Unexpected image exif model: %s != %s", metadata.EXIF.Model, file.model) + if metadata.EXIF.GPSHPositioningError != file.GPSHPositioningError { + t.Fatalf("Unexpected image exif GPSHPositioningError: %s != %s", metadata.EXIF.GPSHPositioningError, file.GPSHPositioningError) } - if metadata.EXIF.Orientation != file.orientation { - t.Fatalf("Unexpected image exif orientation: %d != %d", metadata.EXIF.Orientation, file.orientation) + if metadata.EXIF.GPSVersionID != file.GPSVersionID { + t.Fatalf("Unexpected image exif GPSVersionID: %s != %s", metadata.EXIF.GPSVersionID, file.GPSVersionID) } - if metadata.EXIF.Software != file.software { - t.Fatalf("Unexpected image exif software: %s != %s", metadata.EXIF.Software, file.software) + if metadata.EXIF.InteroperabilityIndex != file.InteroperabilityIndex { + t.Fatalf("Unexpected image exif InteroperabilityIndex: %s != %s", metadata.EXIF.InteroperabilityIndex, file.InteroperabilityIndex) } - if metadata.EXIF.Datetime != file.datetime { - t.Fatalf("Unexpected image exif datetime: %s != %s", metadata.EXIF.Datetime, file.datetime) + if metadata.EXIF.InteroperabilityVersion != file.InteroperabilityVersion { + t.Fatalf("Unexpected image exif InteroperabilityVersion: %s != %s", metadata.EXIF.InteroperabilityVersion, file.InteroperabilityVersion) } } } diff --git a/testdata/test_exif_full.jpg b/testdata/test_exif_full.jpg new file mode 100644 index 0000000..1bb6a75 Binary files /dev/null and b/testdata/test_exif_full.jpg differ diff --git a/vips.go b/vips.go index 23e8676..c2b0143 100644 --- a/vips.go +++ b/vips.go @@ -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] diff --git a/vips.h b/vips.h index 894adf1..c21197d 100644 --- a/vips.h +++ b/vips.h @@ -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_orientation(VipsImage *image) { - int orientation = 0; - const char *exif = vips_exif_tag(image, EXIF_IFD0_ORIENTATION); +vips_exif_tag_to_int(VipsImage *image, const char *tag) { + int value = 0; + const char *exif = vips_exif_tag(image, tag); if (strcmp(exif, "")) { - orientation = atoi(&exif[0]); + value = atoi(&exif[0]); } - return orientation; + return value; } -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); +int +vips_exif_orientation(VipsImage *image) { + return vips_exif_tag_to_int(image, EXIF_IFD0_ORIENTATION); } int