Skip to content

Commit ce34e84

Browse files
Merge pull request #1923 from IldarKhayrutdinov/ifd-pointer
EXIF IDF pointer
2 parents a54a19f + 92cc9fb commit ce34e84

File tree

2 files changed

+44
-18
lines changed

2 files changed

+44
-18
lines changed

src/ImageSharp/Metadata/Profiles/Exif/ExifWriter.cs

Lines changed: 14 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -46,49 +46,42 @@ public ExifWriter(IList<IExifValue> values, ExifParts allowedParts)
4646
public byte[] GetData()
4747
{
4848
const uint startIndex = 0;
49-
uint length;
5049

5150
IExifValue exifOffset = GetOffsetValue(this.ifdValues, this.exifValues, ExifTag.SubIFDOffset);
5251
IExifValue gpsOffset = GetOffsetValue(this.ifdValues, this.gpsValues, ExifTag.GPSIFDOffset);
5352

54-
if (this.ifdValues.Count == 0 && this.exifValues.Count == 0 && this.gpsValues.Count == 0)
55-
{
56-
return Array.Empty<byte>();
57-
}
58-
59-
uint ifdLength = this.GetLength(this.ifdValues) + 4U;
53+
uint ifdLength = this.GetLength(this.ifdValues);
6054
uint exifLength = this.GetLength(this.exifValues);
6155
uint gpsLength = this.GetLength(this.gpsValues);
6256

63-
length = ifdLength + exifLength + gpsLength;
57+
uint length = ifdLength + exifLength + gpsLength;
6458

65-
if (length == 4U)
59+
if (length == 0)
6660
{
6761
return Array.Empty<byte>();
6862
}
6963

7064
// two bytes for the byte Order marker 'II' or 'MM', followed by the number 42 (0x2A) and a 0, making 4 bytes total
7165
length += (uint)ExifConstants.LittleEndianByteOrderMarker.Length;
7266

73-
length += 4 + 2;
67+
// first IFD offset
68+
length += 4;
7469

75-
var result = new byte[length];
70+
byte[] result = new byte[length];
7671

7772
int i = 0;
7873

7974
// The byte order marker for little-endian, followed by the number 42 and a 0
8075
ExifConstants.LittleEndianByteOrderMarker.CopyTo(result.AsSpan(start: i));
8176
i += ExifConstants.LittleEndianByteOrderMarker.Length;
8277

83-
uint ifdOffset = ((uint)i - startIndex) + 4U;
84-
uint thumbnailOffset = ifdOffset + ifdLength + exifLength + gpsLength;
78+
uint ifdOffset = (uint)i - startIndex + 4U;
8579

8680
exifOffset?.TrySetValue(ifdOffset + ifdLength);
8781
gpsOffset?.TrySetValue(ifdOffset + ifdLength + exifLength);
8882

8983
i = WriteUInt32(ifdOffset, result, i);
9084
i = this.WriteHeaders(this.ifdValues, result, i);
91-
i = WriteUInt32(thumbnailOffset, result, i);
9285
i = this.WriteData(startIndex, this.ifdValues, result, i);
9386

9487
if (exifLength > 0)
@@ -103,8 +96,6 @@ public byte[] GetData()
10396
i = this.WriteData(startIndex, this.gpsValues, result, i);
10497
}
10598

106-
WriteUInt16(0, result, i);
107-
10899
return result;
109100
}
110101

@@ -263,14 +254,17 @@ private uint GetLength(IList<IExifValue> values)
263254
{
264255
uint valueLength = GetLength(value);
265256

266-
length += 2 + 2 + 4 + 4;
257+
length += 12;
267258

268259
if (valueLength > 4)
269260
{
270261
length += valueLength;
271262
}
272263
}
273264

265+
// next IFD offset
266+
length += 4;
267+
274268
return length;
275269
}
276270

@@ -361,6 +355,9 @@ private int WriteHeaders(List<IExifValue> values, Span<byte> destination, int of
361355
newOffset += 4;
362356
}
363357

358+
// next IFD offset
359+
newOffset = WriteUInt32(0, destination, newOffset);
360+
364361
return newOffset;
365362
}
366363

tests/ImageSharp.Tests/Metadata/Profiles/Exif/ExifProfileTests.cs

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// Licensed under the Apache License, Version 2.0.
33

44
using System;
5+
using System.Buffers.Binary;
56
using System.Collections.Generic;
67
using System.IO;
78
using System.Linq;
@@ -86,6 +87,18 @@ public void ConstructorEmpty()
8687
new ExifProfile(Array.Empty<byte>());
8788
}
8889

90+
[Fact]
91+
public void EmptyWriter()
92+
{
93+
var profile = new ExifProfile() { Parts = ExifParts.GpsTags };
94+
profile.SetValue(ExifTag.Copyright, "Copyright text");
95+
96+
byte[] bytes = profile.ToByteArray();
97+
98+
Assert.NotNull(bytes);
99+
Assert.Empty(bytes);
100+
}
101+
89102
[Fact]
90103
public void ConstructorCopy()
91104
{
@@ -420,7 +433,7 @@ public void TestArrayValueWithUnspecifiedSize()
420433
Assert.Equal(2, profile.Values.Count(v => (ExifTagValue)(ushort)v.Tag == ExifTagValue.DateTime));
421434

422435
byte[] bytes = profile.ToByteArray();
423-
Assert.Equal(525, bytes.Length);
436+
Assert.Equal(531, bytes.Length);
424437

425438
var profile2 = new ExifProfile(bytes);
426439
Assert.Equal(25, profile2.Values.Count);
@@ -487,6 +500,22 @@ private static ExifProfile CreateExifProfile()
487500
return profile;
488501
}
489502

503+
[Fact]
504+
public void IfdStructure()
505+
{
506+
var exif = new ExifProfile();
507+
exif.SetValue(ExifTag.XPAuthor, Encoding.GetEncoding("UCS-2").GetBytes("Dan Petitt"));
508+
509+
Span<byte> actualBytes = exif.ToByteArray();
510+
511+
// Assert
512+
int ifdOffset = ExifConstants.LittleEndianByteOrderMarker.Length;
513+
Assert.Equal(8U, BinaryPrimitives.ReadUInt32LittleEndian(actualBytes.Slice(ifdOffset, 4)));
514+
515+
int nextIfdPointerOffset = ExifConstants.LittleEndianByteOrderMarker.Length + 4 + 2 + 12;
516+
Assert.Equal(0U, BinaryPrimitives.ReadUInt32LittleEndian(actualBytes.Slice(nextIfdPointerOffset, 4)));
517+
}
518+
490519
internal static ExifProfile GetExifProfile()
491520
{
492521
using Image<Rgba32> image = TestFile.Create(TestImages.Jpeg.Baseline.Floorplan).CreateRgba32Image();

0 commit comments

Comments
 (0)