Skip to content

Commit 94b9962

Browse files
Merge pull request #1812 from SixLabors/af/InternalDetectFormat-DoNotAllocate
stackalloc header buffer in InternalDetectFormat
2 parents a06011a + af90336 commit 94b9962

File tree

1 file changed

+31
-20
lines changed

1 file changed

+31
-20
lines changed

src/ImageSharp/Image.Decode.cs

Lines changed: 31 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -58,31 +58,42 @@ private static IImageFormat InternalDetectFormat(Stream stream, Configuration co
5858
return null;
5959
}
6060

61-
using (IMemoryOwner<byte> buffer = config.MemoryAllocator.Allocate<byte>(headerSize, AllocationOptions.Clean))
61+
// Header sizes are so small, that headersBuffer will be always stackalloc-ed in practice,
62+
// and heap allocation will never happen, there is no need for the usual try-finally ArrayPool dance.
63+
// The array case is only a safety mechanism following stackalloc best practices.
64+
Span<byte> headersBuffer = headerSize > 512 ? new byte[headerSize] : stackalloc byte[headerSize];
65+
long startPosition = stream.Position;
66+
67+
// Read doesn't always guarantee the full returned length so read a byte
68+
// at a time until we get either our count or hit the end of the stream.
69+
int n = 0;
70+
int i;
71+
do
6272
{
63-
Span<byte> bufferSpan = buffer.GetSpan();
64-
long startPosition = stream.Position;
73+
i = stream.Read(headersBuffer, n, headerSize - n);
74+
n += i;
75+
}
76+
while (n < headerSize && i > 0);
6577

66-
// Read doesn't always guarantee the full returned length so read a byte
67-
// at a time until we get either our count or hit the end of the stream.
68-
int n = 0;
69-
int i;
70-
do
78+
stream.Position = startPosition;
79+
80+
// Does the given stream contain enough data to fit in the header for the format
81+
// and does that data match the format specification?
82+
// Individual formats should still check since they are public.
83+
IImageFormat format = null;
84+
foreach (IImageFormatDetector formatDetector in config.ImageFormatsManager.FormatDetectors)
85+
{
86+
if (formatDetector.HeaderSize <= headerSize)
7187
{
72-
i = stream.Read(bufferSpan, n, headerSize - n);
73-
n += i;
88+
IImageFormat attemptFormat = formatDetector.DetectFormat(headersBuffer);
89+
if (attemptFormat != null)
90+
{
91+
format = attemptFormat;
92+
}
7493
}
75-
while (n < headerSize && i > 0);
76-
77-
stream.Position = startPosition;
78-
79-
// Does the given stream contain enough data to fit in the header for the format
80-
// and does that data match the format specification?
81-
// Individual formats should still check since they are public.
82-
return config.ImageFormatsManager.FormatDetectors
83-
.Where(x => x.HeaderSize <= headerSize)
84-
.Select(x => x.DetectFormat(buffer.GetSpan())).LastOrDefault(x => x != null);
8594
}
95+
96+
return format;
8697
}
8798

8899
/// <summary>

0 commit comments

Comments
 (0)