diff --git a/src/ImageSharp/Formats/Heic/HeicEncoderCore.cs b/src/ImageSharp/Formats/Heic/HeicEncoderCore.cs index 11bf586a48..f1efa5a254 100644 --- a/src/ImageSharp/Formats/Heic/HeicEncoderCore.cs +++ b/src/ImageSharp/Formats/Heic/HeicEncoderCore.cs @@ -68,10 +68,12 @@ internal sealed class HeicEncoderCore : IImageEncoderInternals primaryItem.BitsPerPixel = 24; primaryItem.ChannelCount = 3; primaryItem.SetExtent(image.Size); + items.Add(primaryItem); // Create a fake thumbnail, to make our own Decoder happy. HeicItemLink thumbnail = new(Heic4CharCode.thmb, 1u); thumbnail.DestinationIds.Add(1u); + links.Add(thumbnail); } private static int WriteBoxHeader(Span buffer, Heic4CharCode type) @@ -126,7 +128,7 @@ internal sealed class HeicEncoderCore : IImageEncoderInternals bytesWritten += WriteHandlerBox(memory, bytesWritten); bytesWritten += WritePrimaryItemBox(memory, bytesWritten); bytesWritten += WriteItemInfoBox(memory, bytesWritten, items); - bytesWritten += WriteItemReferenceBox(memory, bytesWritten, links); + bytesWritten += WriteItemReferenceBox(memory, bytesWritten, items, links); bytesWritten += WriteItemPropertiesBox(memory, bytesWritten, items); bytesWritten += WriteItemDataBox(memory, bytesWritten); bytesWritten += WriteItemLocationBox(memory, bytesWritten, items); @@ -138,7 +140,7 @@ internal sealed class HeicEncoderCore : IImageEncoderInternals private static int WriteHandlerBox(AutoExpandingMemory memory, int memoryOffset) { - Span buffer = memory.GetSpan(memoryOffset, 24); + Span buffer = memory.GetSpan(memoryOffset, 33); int bytesWritten = WriteBoxHeader(buffer, Heic4CharCode.hdlr, 0, 0); BinaryPrimitives.WriteUInt32BigEndian(buffer[bytesWritten..], 0); bytesWritten += 4; @@ -155,7 +157,7 @@ internal sealed class HeicEncoderCore : IImageEncoderInternals private static int WritePrimaryItemBox(AutoExpandingMemory memory, int memoryOffset) { - Span buffer = memory.GetSpan(memoryOffset, 12); + Span buffer = memory.GetSpan(memoryOffset, 14); int bytesWritten = WriteBoxHeader(buffer, Heic4CharCode.pitm, 0, 0); BinaryPrimitives.WriteUInt16BigEndian(buffer[bytesWritten..], 1); bytesWritten += 2; @@ -166,7 +168,7 @@ internal sealed class HeicEncoderCore : IImageEncoderInternals private static int WriteItemInfoBox(AutoExpandingMemory memory, int memoryOffset, List items) { - Span buffer = memory.GetSpan(memoryOffset, 6 + (items.Count * 9)); + Span buffer = memory.GetSpan(memoryOffset, 14 + (items.Count * 21)); int bytesWritten = WriteBoxHeader(buffer, Heic4CharCode.iinf, 0, 0); BinaryPrimitives.WriteUInt16BigEndian(buffer[bytesWritten..], (ushort)items.Count); bytesWritten += 2; @@ -189,9 +191,9 @@ internal sealed class HeicEncoderCore : IImageEncoderInternals return bytesWritten; } - private static int WriteItemReferenceBox(AutoExpandingMemory memory, int memoryOffset, List links) + private static int WriteItemReferenceBox(AutoExpandingMemory memory, int memoryOffset, List items, List links) { - Span buffer = memory.GetSpan(memoryOffset, 4 + (links.Count << 4)); + Span buffer = memory.GetSpan(memoryOffset, 12 + (links.Count * (12 + (items.Count * 2)))); int bytesWritten = WriteBoxHeader(buffer, Heic4CharCode.iref, 0, 0); foreach (HeicItemLink link in links) { @@ -217,7 +219,7 @@ internal sealed class HeicEncoderCore : IImageEncoderInternals private static int WriteItemPropertiesBox(AutoExpandingMemory memory, int memoryOffset, List items) { const ushort numPropPerItem = 1; - Span buffer = memory.GetSpan(memoryOffset, 100); + Span buffer = memory.GetSpan(memoryOffset, 20); int bytesWritten = WriteBoxHeader(buffer, Heic4CharCode.iprp); // Write 'ipco' box @@ -225,10 +227,11 @@ internal sealed class HeicEncoderCore : IImageEncoderInternals bytesWritten += WriteBoxHeader(buffer[bytesWritten..], Heic4CharCode.ipco); foreach (HeicItem item in items) { - bytesWritten += WriteSpatialExtentPropertyBox(memory, ipcoLengthOffset + bytesWritten, item); + bytesWritten += WriteSpatialExtentPropertyBox(memory, memoryOffset + bytesWritten, item); } BinaryPrimitives.WriteUInt32BigEndian(buffer[ipcoLengthOffset..], (uint)(bytesWritten - ipcoLengthOffset)); + buffer = memory.GetSpan(memoryOffset, bytesWritten + 16 + (5 * items.Count * numPropPerItem)); // Write 'ipma' box int ipmaLengthOffset = bytesWritten; @@ -255,8 +258,8 @@ internal sealed class HeicEncoderCore : IImageEncoderInternals private static int WriteSpatialExtentPropertyBox(AutoExpandingMemory memory, int memoryOffset, HeicItem item) { - Span buffer = memory.GetSpan(memoryOffset, 16); - int bytesWritten = WriteBoxHeader(buffer, Heic4CharCode.ispe); + Span buffer = memory.GetSpan(memoryOffset, 20); + int bytesWritten = WriteBoxHeader(buffer, Heic4CharCode.ispe, 0, 0); BinaryPrimitives.WriteUInt32BigEndian(buffer[bytesWritten..], (uint)item.Extent.Width); bytesWritten += 4; BinaryPrimitives.WriteUInt32BigEndian(buffer[bytesWritten..], (uint)item.Extent.Height); diff --git a/tests/ImageSharp.Tests/Formats/Heic/HeicEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Heic/HeicEncoderTests.cs index 8bfbce973f..3b6087d0a5 100644 --- a/tests/ImageSharp.Tests/Formats/Heic/HeicEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Heic/HeicEncoderTests.cs @@ -23,7 +23,7 @@ public class HeicEncoderTests image.Save(stream, encoder); stream.Position = 0; - using Image encodedImage = (Image)Image.Load(stream); + using Image encodedImage = Image.Load(stream); HeicMetadata heicMetadata = encodedImage.Metadata.GetHeicMetadata(); ImageComparer.Exact.CompareImages(image, encodedImage);