Skip to content

Commit

Permalink
Merge pull request #1923 from IldarKhayrutdinov/ifd-pointer
Browse files Browse the repository at this point in the history
EXIF IDF pointer
  • Loading branch information
JimBobSquarePants authored Jan 9, 2022
2 parents a54a19f + 92cc9fb commit ce34e84
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 18 deletions.
31 changes: 14 additions & 17 deletions src/ImageSharp/Metadata/Profiles/Exif/ExifWriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,49 +46,42 @@ public ExifWriter(IList<IExifValue> values, ExifParts allowedParts)
public byte[] GetData()
{
const uint startIndex = 0;
uint length;

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

if (this.ifdValues.Count == 0 && this.exifValues.Count == 0 && this.gpsValues.Count == 0)
{
return Array.Empty<byte>();
}

uint ifdLength = this.GetLength(this.ifdValues) + 4U;
uint ifdLength = this.GetLength(this.ifdValues);
uint exifLength = this.GetLength(this.exifValues);
uint gpsLength = this.GetLength(this.gpsValues);

length = ifdLength + exifLength + gpsLength;
uint length = ifdLength + exifLength + gpsLength;

if (length == 4U)
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;

length += 4 + 2;
// first IFD offset
length += 4;

var result = new byte[length];
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;
uint thumbnailOffset = ifdOffset + ifdLength + exifLength + gpsLength;
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 = WriteUInt32(thumbnailOffset, result, i);
i = this.WriteData(startIndex, this.ifdValues, result, i);

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

WriteUInt16(0, result, i);

return result;
}

Expand Down Expand Up @@ -263,14 +254,17 @@ private uint GetLength(IList<IExifValue> values)
{
uint valueLength = GetLength(value);

length += 2 + 2 + 4 + 4;
length += 12;

if (valueLength > 4)
{
length += valueLength;
}
}

// next IFD offset
length += 4;

return length;
}

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

// next IFD offset
newOffset = WriteUInt32(0, destination, newOffset);

return newOffset;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0.

using System;
using System.Buffers.Binary;
using System.Collections.Generic;
using System.IO;
using System.Linq;
Expand Down Expand Up @@ -86,6 +87,18 @@ public void ConstructorEmpty()
new ExifProfile(Array.Empty<byte>());
}

[Fact]
public void EmptyWriter()
{
var profile = new ExifProfile() { Parts = ExifParts.GpsTags };
profile.SetValue(ExifTag.Copyright, "Copyright text");

byte[] bytes = profile.ToByteArray();

Assert.NotNull(bytes);
Assert.Empty(bytes);
}

[Fact]
public void ConstructorCopy()
{
Expand Down Expand Up @@ -420,7 +433,7 @@ public void TestArrayValueWithUnspecifiedSize()
Assert.Equal(2, profile.Values.Count(v => (ExifTagValue)(ushort)v.Tag == ExifTagValue.DateTime));

byte[] bytes = profile.ToByteArray();
Assert.Equal(525, bytes.Length);
Assert.Equal(531, bytes.Length);

var profile2 = new ExifProfile(bytes);
Assert.Equal(25, profile2.Values.Count);
Expand Down Expand Up @@ -487,6 +500,22 @@ private static ExifProfile CreateExifProfile()
return profile;
}

[Fact]
public void IfdStructure()
{
var exif = new ExifProfile();
exif.SetValue(ExifTag.XPAuthor, Encoding.GetEncoding("UCS-2").GetBytes("Dan Petitt"));

Span<byte> actualBytes = exif.ToByteArray();

// Assert
int ifdOffset = ExifConstants.LittleEndianByteOrderMarker.Length;
Assert.Equal(8U, BinaryPrimitives.ReadUInt32LittleEndian(actualBytes.Slice(ifdOffset, 4)));

int nextIfdPointerOffset = ExifConstants.LittleEndianByteOrderMarker.Length + 4 + 2 + 12;
Assert.Equal(0U, BinaryPrimitives.ReadUInt32LittleEndian(actualBytes.Slice(nextIfdPointerOffset, 4)));
}

internal static ExifProfile GetExifProfile()
{
using Image<Rgba32> image = TestFile.Create(TestImages.Jpeg.Baseline.Floorplan).CreateRgba32Image();
Expand Down

0 comments on commit ce34e84

Please sign in to comment.