/// <summary> /// Returns the EXIF data. /// </summary> /// <returns> /// The <see cref="T:byte[]"/>. /// </returns> public byte[] GetData() { const uint startIndex = 0; IExifValue exifOffset = GetOffsetValue(this.ifdValues, this.exifValues, ExifTag.SubIFDOffset); IExifValue gpsOffset = GetOffsetValue(this.ifdValues, this.gpsValues, ExifTag.GPSIFDOffset); uint ifdLength = this.GetLength(this.ifdValues); uint exifLength = this.GetLength(this.exifValues); uint gpsLength = this.GetLength(this.gpsValues); uint length = ifdLength + exifLength + gpsLength; if (length == 0) { return(Array.Empty <byte>()); } // two bytes for the byte Order marker 'II' or 'MM', followed by the number 42 (0x2A) and a 0, making 4 bytes total length += (uint)ExifConstants.LittleEndianByteOrderMarker.Length; // first IFD offset length += 4; byte[] result = new byte[length]; int i = 0; // The byte order marker for little-endian, followed by the number 42 and a 0 ExifConstants.LittleEndianByteOrderMarker.CopyTo(result.AsSpan(start: i)); i += ExifConstants.LittleEndianByteOrderMarker.Length; uint ifdOffset = (uint)i - startIndex + 4U; exifOffset?.TrySetValue(ifdOffset + ifdLength); gpsOffset?.TrySetValue(ifdOffset + ifdLength + exifLength); i = WriteUInt32(ifdOffset, result, i); i = this.WriteHeaders(this.ifdValues, result, i); i = this.WriteData(startIndex, this.ifdValues, result, i); if (exifLength > 0) { i = this.WriteHeaders(this.exifValues, result, i); i = this.WriteData(startIndex, this.exifValues, result, i); } if (gpsLength > 0) { i = this.WriteHeaders(this.gpsValues, result, i); i = this.WriteData(startIndex, this.gpsValues, result, i); } return(result); }
public void SetValue(TestImageWriteFormat imageFormat) { Image <Rgba32> image = TestFile.Create(TestImages.Jpeg.Baseline.Floorplan).CreateRgba32Image(); image.Metadata.ExifProfile.SetValue(ExifTag.Software, "ImageSharp"); IExifValue <string> software = image.Metadata.ExifProfile.GetValue(ExifTag.Software); Assert.Equal("ImageSharp", software.Value); // ExifString can set integer values. Assert.True(software.TrySetValue(15)); Assert.False(software.TrySetValue(15F)); image.Metadata.ExifProfile.SetValue(ExifTag.ShutterSpeedValue, new SignedRational(75.55)); IExifValue <SignedRational> shutterSpeed = image.Metadata.ExifProfile.GetValue(ExifTag.ShutterSpeedValue); Assert.Equal(new SignedRational(7555, 100), shutterSpeed.Value); Assert.False(shutterSpeed.TrySetValue(75)); image.Metadata.ExifProfile.SetValue(ExifTag.XResolution, new Rational(150.0)); // We also need to change this value because this overrides XResolution when the image is written. image.Metadata.HorizontalResolution = 150.0; IExifValue <Rational> xResolution = image.Metadata.ExifProfile.GetValue(ExifTag.XResolution); Assert.Equal(new Rational(150, 1), xResolution.Value); Assert.False(xResolution.TrySetValue("ImageSharp")); image.Metadata.ExifProfile.SetValue(ExifTag.ReferenceBlackWhite, null); IExifValue <Rational[]> referenceBlackWhite = image.Metadata.ExifProfile.GetValue(ExifTag.ReferenceBlackWhite); Assert.Null(referenceBlackWhite.Value); var expectedLatitude = new Rational[] { new Rational(12.3), new Rational(4.56), new Rational(789.0) }; image.Metadata.ExifProfile.SetValue(ExifTag.GPSLatitude, expectedLatitude); IExifValue <Rational[]> latitude = image.Metadata.ExifProfile.GetValue(ExifTag.GPSLatitude); Assert.Equal(expectedLatitude, latitude.Value); int profileCount = image.Metadata.ExifProfile.Values.Count; image = WriteAndRead(image, imageFormat); Assert.NotNull(image.Metadata.ExifProfile); // Should be 3 less. // 1 x due to setting of null "ReferenceBlackWhite" value. // 2 x due to use of non-standard padding tag 0xEA1C listed in EXIF Tool. We can read those values but adhere // strictly to the 2.3.1 specification when writing. (TODO: Support 2.3.2) // https://exiftool.org/TagNames/EXIF.html Assert.Equal(profileCount - 3, image.Metadata.ExifProfile.Values.Count); software = image.Metadata.ExifProfile.GetValue(ExifTag.Software); Assert.Equal("15", software.Value); shutterSpeed = image.Metadata.ExifProfile.GetValue(ExifTag.ShutterSpeedValue); Assert.Equal(new SignedRational(75.55), shutterSpeed.Value); xResolution = image.Metadata.ExifProfile.GetValue(ExifTag.XResolution); Assert.Equal(new Rational(150.0), xResolution.Value); referenceBlackWhite = image.Metadata.ExifProfile.GetValue(ExifTag.ReferenceBlackWhite); Assert.Null(referenceBlackWhite); latitude = image.Metadata.ExifProfile.GetValue(ExifTag.GPSLatitude); Assert.Equal(expectedLatitude, latitude.Value); image.Metadata.ExifProfile.Parts = ExifParts.ExifTags; image = WriteAndRead(image, imageFormat); Assert.NotNull(image.Metadata.ExifProfile); Assert.Equal(8, image.Metadata.ExifProfile.Values.Count); Assert.NotNull(image.Metadata.ExifProfile.GetValue(ExifTag.ColorSpace)); Assert.True(image.Metadata.ExifProfile.RemoveValue(ExifTag.ColorSpace)); Assert.False(image.Metadata.ExifProfile.RemoveValue(ExifTag.ColorSpace)); Assert.Null(image.Metadata.ExifProfile.GetValue(ExifTag.ColorSpace)); Assert.Equal(7, image.Metadata.ExifProfile.Values.Count); }
public void SetValue(TestImageWriteFormat imageFormat, int expectedProfileValueCount) { Image <Rgba32> image = TestFile.Create(TestImages.Jpeg.Baseline.Floorplan).CreateRgba32Image(); image.Metadata.ExifProfile.SetValue(ExifTag.Software, "ImageSharp"); IExifValue <string> software = image.Metadata.ExifProfile.GetValue(ExifTag.Software); Assert.Equal("ImageSharp", software.Value); // ExifString can set integer values. Assert.True(software.TrySetValue(15)); Assert.False(software.TrySetValue(15F)); image.Metadata.ExifProfile.SetValue(ExifTag.ShutterSpeedValue, new SignedRational(75.55)); IExifValue <SignedRational> shutterSpeed = image.Metadata.ExifProfile.GetValue(ExifTag.ShutterSpeedValue); Assert.Equal(new SignedRational(7555, 100), shutterSpeed.Value); Assert.False(shutterSpeed.TrySetValue(75)); image.Metadata.ExifProfile.SetValue(ExifTag.XResolution, new Rational(150.0)); // We also need to change this value because this overrides XResolution when the image is written. image.Metadata.HorizontalResolution = 150.0; IExifValue <Rational> xResolution = image.Metadata.ExifProfile.GetValue(ExifTag.XResolution); Assert.Equal(new Rational(150, 1), xResolution.Value); Assert.False(xResolution.TrySetValue("ImageSharp")); image.Metadata.ExifProfile.SetValue(ExifTag.ReferenceBlackWhite, null); IExifValue <Rational[]> referenceBlackWhite = image.Metadata.ExifProfile.GetValue(ExifTag.ReferenceBlackWhite); Assert.Null(referenceBlackWhite.Value); var expectedLatitude = new Rational[] { new Rational(12.3), new Rational(4.56), new Rational(789.0) }; image.Metadata.ExifProfile.SetValue(ExifTag.GPSLatitude, expectedLatitude); IExifValue <Rational[]> latitude = image.Metadata.ExifProfile.GetValue(ExifTag.GPSLatitude); Assert.Equal(expectedLatitude, latitude.Value); // todo: duplicate tags Assert.Equal(2, image.Metadata.ExifProfile.Values.Count(v => (ushort)v.Tag == 59932)); image = WriteAndRead(image, imageFormat); Assert.NotNull(image.Metadata.ExifProfile); Assert.Equal(0, image.Metadata.ExifProfile.Values.Count(v => (ushort)v.Tag == 59932)); Assert.Equal(expectedProfileValueCount, image.Metadata.ExifProfile.Values.Count); software = image.Metadata.ExifProfile.GetValue(ExifTag.Software); Assert.Equal("15", software.Value); shutterSpeed = image.Metadata.ExifProfile.GetValue(ExifTag.ShutterSpeedValue); Assert.Equal(new SignedRational(75.55), shutterSpeed.Value); xResolution = image.Metadata.ExifProfile.GetValue(ExifTag.XResolution); Assert.Equal(new Rational(150.0), xResolution.Value); referenceBlackWhite = image.Metadata.ExifProfile.GetValue(ExifTag.ReferenceBlackWhite); Assert.Null(referenceBlackWhite); latitude = image.Metadata.ExifProfile.GetValue(ExifTag.GPSLatitude); Assert.Equal(expectedLatitude, latitude.Value); image.Dispose(); }