Skip to content

Commit 818412b

Browse files
Merge branch 'main' into js/jpeg-icc-normalize
2 parents b860f55 + 1226eb5 commit 818412b

File tree

13 files changed

+73
-28
lines changed

13 files changed

+73
-28
lines changed

src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ public void Encode<TPixel>(Image<TPixel> image, Stream stream, CancellationToken
5858
Guard.NotNull(image, nameof(image));
5959
Guard.NotNull(stream, nameof(stream));
6060

61-
if (image.Width >= JpegConstants.MaxLength || image.Height >= JpegConstants.MaxLength)
61+
if (image.Width > JpegConstants.MaxLength || image.Height > JpegConstants.MaxLength)
6262
{
6363
JpegThrowHelper.ThrowDimensionsTooLarge(image.Width, image.Height);
6464
}

src/ImageSharp/Formats/Png/PngDecoderCore.cs

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,11 @@ internal sealed class PngDecoderCore : ImageDecoderCore
131131
/// </summary>
132132
private readonly int maxUncompressedLength;
133133

134+
/// <summary>
135+
/// A value indicating whether the image data has been read.
136+
/// </summary>
137+
private bool hasImageData;
138+
134139
/// <summary>
135140
/// Initializes a new instance of the <see cref="PngDecoderCore"/> class.
136141
/// </summary>
@@ -749,7 +754,11 @@ private void ReadScanlines<TPixel>(
749754
where TPixel : unmanaged, IPixel<TPixel>
750755
{
751756
using ZlibInflateStream inflateStream = new(this.currentStream, getData);
752-
inflateStream.AllocateNewBytes(chunkLength, true);
757+
if (!inflateStream.AllocateNewBytes(chunkLength, !this.hasImageData))
758+
{
759+
return;
760+
}
761+
753762
DeflateStream dataStream = inflateStream.CompressedStream!;
754763

755764
if (this.header.InterlaceMethod is PngInterlaceMode.Adam7)
@@ -803,7 +812,7 @@ private void DecodePixelData<TPixel>(
803812
int bytesRead = compressedStream.Read(scanSpan, currentRowBytesRead, bytesPerFrameScanline - currentRowBytesRead);
804813
if (bytesRead <= 0)
805814
{
806-
return;
815+
goto EXIT;
807816
}
808817

809818
currentRowBytesRead += bytesRead;
@@ -848,6 +857,7 @@ private void DecodePixelData<TPixel>(
848857
}
849858

850859
EXIT:
860+
this.hasImageData = true;
851861
blendMemory?.Dispose();
852862
}
853863

@@ -906,7 +916,7 @@ private void DecodeInterlacedPixelData<TPixel>(
906916
int bytesRead = compressedStream.Read(this.scanline.GetSpan(), currentRowBytesRead, bytesPerInterlaceScanline - currentRowBytesRead);
907917
if (bytesRead <= 0)
908918
{
909-
return;
919+
goto EXIT;
910920
}
911921

912922
currentRowBytesRead += bytesRead;
@@ -979,6 +989,7 @@ private void DecodeInterlacedPixelData<TPixel>(
979989
}
980990

981991
EXIT:
992+
this.hasImageData = true;
982993
blendMemory?.Dispose();
983994
}
984995

src/ImageSharp/Formats/Webp/Lossless/Vp8LEncoder.cs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -371,9 +371,6 @@ public int EncodeAlphaImageData<TPixel>(Buffer2DRegion<TPixel> frame, IMemoryOwn
371371
/// <param name="inputImgHeight">The input image height.</param>
372372
private void WriteImageSize(int inputImgWidth, int inputImgHeight)
373373
{
374-
Guard.MustBeLessThan(inputImgWidth, WebpConstants.MaxDimension, nameof(inputImgWidth));
375-
Guard.MustBeLessThan(inputImgHeight, WebpConstants.MaxDimension, nameof(inputImgHeight));
376-
377374
uint width = (uint)inputImgWidth - 1;
378375
uint height = (uint)inputImgHeight - 1;
379376

src/ImageSharp/Formats/Webp/WebpDecoderCore.cs

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,7 @@ private WebpImageInfo ReadVp8Info(BufferedReadStream stream, ImageMetadata metad
220220
else
221221
{
222222
// Ignore unknown chunks.
223-
uint chunkSize = ReadChunkSize(stream, buffer);
223+
uint chunkSize = ReadChunkSize(stream, buffer, false);
224224
stream.Skip((int)chunkSize);
225225
}
226226
}
@@ -498,17 +498,24 @@ private static WebpChunkType ReadChunkType(BufferedReadStream stream, Span<byte>
498498
/// </summary>
499499
/// <param name="stream">The stream to decode from.</param>
500500
/// <param name="buffer">Temporary buffer.</param>
501+
/// <param name="required">If true, the chunk size is required to be read, otherwise it can be skipped.</param>
501502
/// <returns>The chunk size in bytes.</returns>
502503
/// <exception cref="ImageFormatException">Invalid data.</exception>
503-
private static uint ReadChunkSize(BufferedReadStream stream, Span<byte> buffer)
504+
private static uint ReadChunkSize(BufferedReadStream stream, Span<byte> buffer, bool required = true)
504505
{
505506
if (stream.Read(buffer, 0, 4) == 4)
506507
{
507508
uint chunkSize = BinaryPrimitives.ReadUInt32LittleEndian(buffer);
508509
return (chunkSize % 2 == 0) ? chunkSize : chunkSize + 1;
509510
}
510511

511-
throw new ImageFormatException("Invalid Webp data.");
512+
if (required)
513+
{
514+
throw new ImageFormatException("Invalid Webp data.");
515+
}
516+
517+
// Return the size of the remaining data in the stream.
518+
return (uint)(stream.Length - stream.Position);
512519
}
513520

514521
/// <inheritdoc/>

src/ImageSharp/Formats/Webp/WebpEncoderCore.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,11 @@ public void Encode<TPixel>(Image<TPixel> image, Stream stream, CancellationToken
132132
Guard.NotNull(image, nameof(image));
133133
Guard.NotNull(stream, nameof(stream));
134134

135+
if (image.Width > WebpConstants.MaxDimension || image.Height > WebpConstants.MaxDimension)
136+
{
137+
WebpThrowHelper.ThrowDimensionsTooLarge(image.Width, image.Height);
138+
}
139+
135140
bool lossless;
136141
if (this.fileFormat is not null)
137142
{

src/ImageSharp/Formats/Webp/WebpThrowHelper.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,7 @@ internal static class WebpThrowHelper
1818

1919
[DoesNotReturn]
2020
public static void ThrowInvalidImageDimensions(string errorMessage) => throw new InvalidImageContentException(errorMessage);
21+
22+
[DoesNotReturn]
23+
public static void ThrowDimensionsTooLarge(int width, int height) => throw new ImageFormatException($"Image is too large to encode at {width}x{height} for WEBP format.");
2124
}

tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -719,10 +719,20 @@ public void Decode_BadPalette(string file)
719719
[Theory]
720720
[WithFile(TestImages.Png.Issue2752, PixelTypes.Rgba32)]
721721
public void CanDecodeJustOneFrame<TPixel>(TestImageProvider<TPixel> provider)
722-
where TPixel : unmanaged, IPixel<TPixel>
722+
where TPixel : unmanaged, IPixel<TPixel>
723723
{
724724
DecoderOptions options = new() { MaxFrames = 1 };
725725
using Image<TPixel> image = provider.GetImage(PngDecoder.Instance, options);
726726
Assert.Equal(1, image.Frames.Count);
727727
}
728+
729+
[Theory]
730+
[WithFile(TestImages.Png.Issue2924, PixelTypes.Rgba32)]
731+
public void CanDecode_Issue2924<TPixel>(TestImageProvider<TPixel> provider)
732+
where TPixel : unmanaged, IPixel<TPixel>
733+
{
734+
using Image<TPixel> image = provider.GetImage(PngDecoder.Instance);
735+
image.DebugSave(provider);
736+
image.CompareToReferenceOutput(provider);
737+
}
728738
}

tests/ImageSharp.Tests/Formats/WebP/WebpDecoderTests.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -549,4 +549,14 @@ public void Identify_VerifyRatio(string imagePath)
549549
Assert.Equal(37.8, meta.VerticalResolution);
550550
Assert.Equal(PixelResolutionUnit.PixelsPerCentimeter, meta.ResolutionUnits);
551551
}
552+
553+
[Theory]
554+
[WithFile(Lossy.Issue2925, PixelTypes.Rgba32)]
555+
public void WebpDecoder_CanDecode_Issue2925<TPixel>(TestImageProvider<TPixel> provider)
556+
where TPixel : unmanaged, IPixel<TPixel>
557+
{
558+
using Image<TPixel> image = provider.GetImage(WebpDecoder.Instance);
559+
image.DebugSave(provider);
560+
image.CompareToOriginal(provider, ReferenceDecoder);
561+
}
552562
}

tests/ImageSharp.Tests/TestImages.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,9 @@ public static class Png
160160
// Issue 2752: https://github.com/SixLabors/ImageSharp/issues/2752
161161
public const string Issue2752 = "Png/issues/Issue_2752.png";
162162

163+
// Issue 2924: https://github.com/SixLabors/ImageSharp/issues/2924
164+
public const string Issue2924 = "Png/issues/Issue_2924.png";
165+
163166
public static class Bad
164167
{
165168
public const string MissingDataChunk = "Png/xdtn0g01.png";
@@ -871,6 +874,7 @@ public static class Lossy
871874
public const string Issue2763 = "Webp/issues/Issue2763.png";
872875
public const string Issue2801 = "Webp/issues/Issue2801.webp";
873876
public const string Issue2866 = "Webp/issues/Issue2866.webp";
877+
public const string Issue2925 = "Webp/issues/Issue2925.webp";
874878
}
875879

876880
public const string AlphaBlend = "Webp/alpha-blend.webp";

tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs

Lines changed: 6 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -59,11 +59,6 @@ public static Image DebugSave(
5959
bool appendSourceFileOrDescription = true,
6060
IImageEncoder encoder = null)
6161
{
62-
if (TestEnvironment.RunsWithCodeCoverage)
63-
{
64-
return image;
65-
}
66-
6762
provider.Utility.SaveTestOutputFile(
6863
image,
6964
extension,
@@ -112,11 +107,6 @@ public static Image<TPixel> DebugSaveMultiFrame<TPixel>(
112107
Func<int, int, bool> predicate = null)
113108
where TPixel : unmanaged, IPixel<TPixel>
114109
{
115-
if (TestEnvironment.RunsWithCodeCoverage)
116-
{
117-
return image;
118-
}
119-
120110
provider.Utility.SaveTestOutputFileMultiFrame(
121111
image,
122112
extension,
@@ -298,24 +288,23 @@ public static Image<TPixel> CompareDebugOutputToReferenceOutputMultiFrame<TPixel
298288
appendPixelTypeToFileName,
299289
predicate: predicate);
300290

301-
using (Image<TPixel> debugImage = GetDebugOutputImageMultiFrame<TPixel>(
291+
using Image<TPixel> debugImage = GetDebugOutputImageMultiFrame<TPixel>(
302292
provider,
303293
image.Frames.Count,
304294
testOutputDetails,
305295
extension,
306296
appendPixelTypeToFileName,
307-
predicate: predicate))
297+
predicate: predicate);
308298

309-
using (Image<TPixel> referenceImage = GetReferenceOutputImageMultiFrame<TPixel>(
299+
using Image<TPixel> referenceImage = GetReferenceOutputImageMultiFrame<TPixel>(
310300
provider,
311301
image.Frames.Count,
312302
testOutputDetails,
313303
extension,
314304
appendPixelTypeToFileName,
315-
predicate: predicate))
316-
{
317-
comparer.VerifySimilarity(referenceImage, debugImage);
318-
}
305+
predicate: predicate);
306+
307+
comparer.VerifySimilarity(referenceImage, debugImage);
319308

320309
return image;
321310
}

0 commit comments

Comments
 (0)