Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
7781fbd
Validate decoded image dimensions
JimBobSquarePants Sep 4, 2026
23ed0b0
Reject duplicate PNG headers
JimBobSquarePants Sep 4, 2026
ea0475e
Use wide arithmetic for PNG scanline lengths
JimBobSquarePants Sep 4, 2026
0446ba0
Cover large PNG average-filter scanlines
JimBobSquarePants Sep 4, 2026
2b52b55
Validate WebP metadata chunk lengths
JimBobSquarePants Sep 4, 2026
14ddc15
Validate embedded profile extents
JimBobSquarePants Sep 4, 2026
84613d4
Apply EXIF part selection when encoding WebP
JimBobSquarePants Sep 4, 2026
8de892a
Validate ICC CLUT storage before allocation
JimBobSquarePants Sep 4, 2026
73d8e02
Reject undersized ICC tag entries
JimBobSquarePants Sep 4, 2026
92b12d7
Bound BigTIFF directory entry counts
JimBobSquarePants Sep 4, 2026
c4c4bf2
Clamp histogram luminance indices
JimBobSquarePants Sep 4, 2026
a9498c6
Size CCITT encoder output buffers
JimBobSquarePants Sep 4, 2026
cdc79d0
Cover narrow CCITT Group 4 re-encoding
JimBobSquarePants Sep 4, 2026
b03f0ed
Reject unsupported ICC conversion channels
JimBobSquarePants Sep 4, 2026
3c43cf5
Reject short EXR ZIP output
JimBobSquarePants Sep 4, 2026
6ed2a27
Handle partial EXR scanline blocks
JimBobSquarePants Sep 4, 2026
18532d7
Normalize metadata extents and preserve decoder recovery policies
JimBobSquarePants Sep 4, 2026
b335b8a
Apply EXIF part selection at serialization boundary
JimBobSquarePants Sep 4, 2026
584b662
Restore WebP ICC framing comments
JimBobSquarePants Sep 4, 2026
8d48d34
Clamp nonfinite floating-point pixel conversions
JimBobSquarePants Sep 5, 2026
6f9d169
Initialize omitted EXR color channels
JimBobSquarePants Sep 5, 2026
f113fa8
Honor EXR image data recovery without exposing incomplete blocks
JimBobSquarePants Sep 5, 2026
ffd1372
Validate EXR block rows relative to the data window
JimBobSquarePants Sep 5, 2026
4b73eaa
Cover complete ICC CLUT payload and conversion controls
JimBobSquarePants Sep 5, 2026
906f037
Verify CCITT pixels with supplied narrow-image fixtures
JimBobSquarePants Sep 5, 2026
c5babb8
Honor PNG ancillary policy for invalid compressed metadata
JimBobSquarePants Sep 5, 2026
b11f2eb
Handle incomplete EXR zlib headers
JimBobSquarePants Sep 5, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ public ClutCalculator(IccClut clut)
Guard.NotNull(clut, nameof(clut));
Guard.MustBeGreaterThan(clut.InputChannelCount, 0, nameof(clut.InputChannelCount));
Guard.MustBeGreaterThan(clut.OutputChannelCount, 0, nameof(clut.OutputChannelCount));
if (clut.InputChannelCount > 4 || clut.OutputChannelCount > 4)
{
throw new InvalidIccProfileException("ICC conversion supports at most four input and output channels.");
}

this.inputCount = clut.InputChannelCount;
this.outputCount = clut.OutputChannelCount;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,11 @@ private static Vector4 CalculateLut(LutCalculator[] lut, Vector4 value)

private void Init(IccLut[] inputCurve, IccLut[] outputCurve, IccClut clut, Matrix4x4 matrix)
{
if (inputCurve.Length > 4 || outputCurve.Length > 4)
{
throw new InvalidIccProfileException("ICC conversion supports at most four input and output channels.");
}

this.inputCurve = InitLut(inputCurve);
this.outputCurve = InitLut(outputCurve);
this.clutCalculator = new ClutCalculator(clut);
Expand Down
4 changes: 4 additions & 0 deletions src/ImageSharp/ColorProfiles/Icc/Calculators/TrcCalculator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ internal class TrcCalculator : IVector4Calculator
public TrcCalculator(IccTagDataEntry[] entries, bool inverted)
{
Guard.NotNull(entries, nameof(entries));
if (entries.Length > 4)
{
throw new InvalidIccProfileException("ICC conversion supports at most four tone response curves.");
}

this.calculators = new ISingleCalculator[entries.Length];
for (int i = 0; i < entries.Length; i++)
Expand Down
72 changes: 72 additions & 0 deletions src/ImageSharp/Common/Extensions/BufferedReadStreamExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.

using SixLabors.ImageSharp.IO;

namespace SixLabors.ImageSharp;

/// <summary>
/// Extension methods for the <see cref="BufferedReadStream"/> type.
/// </summary>
internal static class BufferedReadStreamExtensions
{
/// <summary>
/// Determines whether the complete read range is contained in the stream.
/// </summary>
/// <param name="stream">The stream containing the data.</param>
/// <param name="offset">The absolute start of the range.</param>
/// <param name="length">The number of bytes in the range.</param>
/// <returns>Whether the range is contained in the stream.</returns>
public static bool IsReadRangeValid(this BufferedReadStream stream, long offset, ulong length)
{
// Compare the offset first so subtraction cannot underflow, and avoid
// adding an untrusted length to the offset where it could wrap around.
ulong streamLength = (ulong)stream.Length;
return (ulong)offset <= streamLength && length <= streamLength - (ulong)offset;
}

/// <summary>
/// Gets a buffer length when the complete read fits in both the stream and an integer-sized buffer.
/// </summary>
/// <param name="stream">The stream containing the data.</param>
/// <param name="length">The declared length in bytes.</param>
/// <param name="bufferLength">The validated length, or zero when the range is invalid.</param>
/// <returns>Whether the complete read is valid.</returns>
public static bool TryGetReadLength(this BufferedReadStream stream, ulong length, out int bufferLength)
{
if (length > int.MaxValue || !stream.IsReadRangeValid(stream.Position, length))
{
bufferLength = 0;
return false;
}

bufferLength = (int)length;
return true;
}

/// <summary>
/// Reads data from the stream into a slice of the provided buffer.
/// </summary>
/// <param name="stream">The stream.</param>
/// <param name="buffer">The buffer.</param>
/// <param name="offset">The offset within the buffer where bytes are read into.</param>
/// <param name="count">The number of bytes, if available, to read.</param>
/// <returns>The actual number of bytes read.</returns>
public static int Read(this BufferedReadStream stream, Span<byte> buffer, int offset, int count)
=> stream.Read(buffer.Slice(offset, count));

/// <summary>
/// Advances the stream by the specified number of bytes. Nonpositive counts are ignored.
/// </summary>
/// <param name="stream">The stream.</param>
/// <param name="count">The number of bytes to skip.</param>
public static void Skip(this BufferedReadStream stream, int count)
{
if (count > 0)
{
// BufferedReadStream is always seekable; its position setter preserves
// buffered data when the destination is inside the current buffer.
stream.Position += count;
}
}
}
51 changes: 0 additions & 51 deletions src/ImageSharp/Common/Extensions/StreamExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.

using System.Buffers;

namespace SixLabors.ImageSharp;

/// <summary>
Expand All @@ -19,53 +17,4 @@ internal static class StreamExtensions
/// <param name="count">The number of bytes to write to the stream.</param>
public static void Write(this Stream stream, Span<byte> buffer, int offset, int count)
=> stream.Write(buffer.Slice(offset, count));

/// <summary>
/// Reads data from a stream into the provided buffer.
/// </summary>
/// <param name="stream">The stream.</param>
/// <param name="buffer">The buffer.</param>
/// <param name="offset">The offset within the buffer where the bytes are read into.</param>
/// <param name="count">The number of bytes, if available, to read.</param>
/// <returns>The actual number of bytes read.</returns>
public static int Read(this Stream stream, Span<byte> buffer, int offset, int count)
=> stream.Read(buffer.Slice(offset, count));

/// <summary>
/// Skips the number of bytes in the given stream.
/// </summary>
/// <param name="stream">The stream.</param>
/// <param name="count">A byte offset relative to the origin parameter.</param>
public static void Skip(this Stream stream, int count)
{
if (count < 1)
{
return;
}

if (stream.CanSeek)
{
stream.Seek(count, SeekOrigin.Current);
return;
}

byte[] buffer = ArrayPool<byte>.Shared.Rent(count);
try
{
while (count > 0)
{
int bytesRead = stream.Read(buffer, 0, count);
if (bytesRead == 0)
{
break;
}

count -= bytesRead;
}
}
finally
{
ArrayPool<byte>.Shared.Return(buffer);
}
}
}
3 changes: 1 addition & 2 deletions src/ImageSharp/Common/Helpers/ColorNumerics.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,7 @@ internal static class ColorNumerics
/// The number of luminance levels (256 for 8 bit, 65536 for 16 bit grayscale images).
/// </param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int GetBT709Luminance(Vector4 vector, int luminanceLevels)
=> (int)MathF.Round(Vector4.Dot(vector, Bt709) * (luminanceLevels - 1));
public static int GetBT709Luminance(Vector4 vector, int luminanceLevels) => (int)MathF.Round(Vector4.Dot(vector, Bt709) * (luminanceLevels - 1));

/// <summary>
/// Gets the luminance from the rgb components using the formula
Expand Down
Loading
Loading