Skip to content

Commit 07fd936

Browse files
Merge pull request #2599 from SixLabors/js/fix-2595
Use source length as bounds when unpacking RGB planes
2 parents 0b36698 + d9ac175 commit 07fd936

File tree

3 files changed

+47
-10
lines changed

3 files changed

+47
-10
lines changed

src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Rgb24.PixelOperations.cs

+4-1
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@ internal override void UnpackIntoRgbPlanes(
4040
Span<float> greenChannel,
4141
Span<float> blueChannel,
4242
ReadOnlySpan<Rgb24> source)
43-
=> SimdUtils.UnpackToRgbPlanes(redChannel, greenChannel, blueChannel, source);
43+
{
44+
GuardUnpackIntoRgbPlanes(redChannel, greenChannel, blueChannel, source);
45+
SimdUtils.UnpackToRgbPlanes(redChannel, greenChannel, blueChannel, source);
46+
}
4447
}
4548
}

src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs

+13-3
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ public virtual void To<TDestinationPixel>(
165165
}
166166

167167
/// <summary>
168-
/// Bulk operation that packs 3 seperate RGB channels to <paramref name="destination"/>.
168+
/// Bulk operation that packs 3 separate RGB channels to <paramref name="destination"/>.
169169
/// The destination must have a padding of 3.
170170
/// </summary>
171171
/// <param name="redChannel">A <see cref="ReadOnlySpan{T}"/> to the red values.</param>
@@ -198,7 +198,7 @@ internal virtual void PackFromRgbPlanes(
198198

199199
/// <summary>
200200
/// Bulk operation that unpacks pixels from <paramref name="source"/>
201-
/// into 3 seperate RGB channels. The destination must have a padding of 3.
201+
/// into 3 separate RGB channels.
202202
/// </summary>
203203
/// <param name="redChannel">A <see cref="ReadOnlySpan{T}"/> to the red values.</param>
204204
/// <param name="greenChannel">A <see cref="ReadOnlySpan{T}"/> to the green values.</param>
@@ -210,7 +210,9 @@ internal virtual void UnpackIntoRgbPlanes(
210210
Span<float> blueChannel,
211211
ReadOnlySpan<TPixel> source)
212212
{
213-
int count = redChannel.Length;
213+
GuardUnpackIntoRgbPlanes(redChannel, greenChannel, blueChannel, source);
214+
215+
int count = source.Length;
214216

215217
Rgba32 rgba32 = default;
216218

@@ -227,6 +229,14 @@ internal virtual void UnpackIntoRgbPlanes(
227229
}
228230
}
229231

232+
[MethodImpl(InliningOptions.ShortMethod)]
233+
internal static void GuardUnpackIntoRgbPlanes(Span<float> redChannel, Span<float> greenChannel, Span<float> blueChannel, ReadOnlySpan<TPixel> source)
234+
{
235+
Guard.IsTrue(greenChannel.Length == redChannel.Length, nameof(greenChannel), "Channels must be of same size!");
236+
Guard.IsTrue(blueChannel.Length == redChannel.Length, nameof(blueChannel), "Channels must be of same size!");
237+
Guard.IsTrue(source.Length <= redChannel.Length, nameof(source), "'source' span should not be bigger than the destination channels!");
238+
}
239+
230240
[MethodImpl(InliningOptions.ShortMethod)]
231241
internal static void GuardPackFromRgbPlanes(ReadOnlySpan<byte> greenChannel, ReadOnlySpan<byte> blueChannel, Span<TPixel> destination, int count)
232242
{

tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.cs

+30-6
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
using SixLabors.ImageSharp.Formats.Jpeg;
55
using SixLabors.ImageSharp.PixelFormats;
6+
using SixLabors.ImageSharp.Processing;
67
using SixLabors.ImageSharp.Tests.TestUtilities;
78
using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison;
89

@@ -87,7 +88,7 @@ public void EncodeBaseline_NonInterleavedMode<TPixel>(TestImageProvider<TPixel>
8788
{
8889
using Image<TPixel> image = provider.GetImage();
8990

90-
var encoder = new JpegEncoder
91+
JpegEncoder encoder = new()
9192
{
9293
Quality = quality,
9394
ColorType = colorType,
@@ -164,8 +165,8 @@ public void EncodeBaseline_WorksWithDiscontiguousBuffers<TPixel>(TestImageProvid
164165
[InlineData(JpegEncodingColor.YCbCrRatio444)]
165166
public async Task Encode_IsCancellable(JpegEncodingColor colorType)
166167
{
167-
var cts = new CancellationTokenSource();
168-
using var pausedStream = new PausedStream(new MemoryStream());
168+
CancellationTokenSource cts = new();
169+
using PausedStream pausedStream = new(new MemoryStream());
169170
pausedStream.OnWaiting(s =>
170171
{
171172
// after some writing
@@ -181,14 +182,37 @@ public async Task Encode_IsCancellable(JpegEncodingColor colorType)
181182
}
182183
});
183184

184-
using var image = new Image<Rgba32>(5000, 5000);
185+
using Image<Rgba32> image = new(5000, 5000);
185186
await Assert.ThrowsAsync<TaskCanceledException>(async () =>
186187
{
187-
var encoder = new JpegEncoder() { ColorType = colorType };
188+
JpegEncoder encoder = new() { ColorType = colorType };
188189
await image.SaveAsync(pausedStream, encoder, cts.Token);
189190
});
190191
}
191192

193+
// https://github.com/SixLabors/ImageSharp/issues/2595
194+
[Theory]
195+
[WithFile(TestImages.Jpeg.Baseline.ForestBridgeDifferentComponentsQuality, PixelTypes.Bgra32)]
196+
[WithFile(TestImages.Jpeg.Baseline.ForestBridgeDifferentComponentsQuality, PixelTypes.Rgb24)]
197+
public static void Issue2595<TPixel>(TestImageProvider<TPixel> provider)
198+
where TPixel : unmanaged, IPixel<TPixel>
199+
{
200+
using Image<TPixel> image = provider.GetImage();
201+
image.Mutate(x => x.Crop(132, 1606));
202+
203+
int[] quality = new int[] { 100, 50 };
204+
JpegEncodingColor[] colors = new[] { JpegEncodingColor.YCbCrRatio444, JpegEncodingColor.YCbCrRatio420 };
205+
for (int i = 0; i < quality.Length; i++)
206+
{
207+
int q = quality[i];
208+
for (int j = 0; j < colors.Length; j++)
209+
{
210+
JpegEncodingColor c = colors[j];
211+
image.VerifyEncoder(provider, "jpeg", $"{q}-{c}", new JpegEncoder() { Quality = q, ColorType = c }, GetComparer(q, c));
212+
}
213+
}
214+
}
215+
192216
/// <summary>
193217
/// Anton's SUPER-SCIENTIFIC tolerance threshold calculation
194218
/// </summary>
@@ -225,7 +249,7 @@ private static void TestJpegEncoderCore<TPixel>(TestImageProvider<TPixel> provid
225249
{
226250
using Image<TPixel> image = provider.GetImage();
227251

228-
var encoder = new JpegEncoder
252+
JpegEncoder encoder = new()
229253
{
230254
Quality = quality,
231255
ColorType = colorType

0 commit comments

Comments
 (0)