diff --git a/.github/ISSUE_TEMPLATE/commercial-bug-report.yml b/.github/ISSUE_TEMPLATE/commercial-bug-report.yml
index e96677b24..6b4d914d7 100644
--- a/.github/ISSUE_TEMPLATE/commercial-bug-report.yml
+++ b/.github/ISSUE_TEMPLATE/commercial-bug-report.yml
@@ -4,6 +4,20 @@ description: |
Please contact help@sixlabors.com for issues requiring private support.
labels: ["commercial", "needs triage"]
body:
+- type: checkboxes
+ attributes:
+ label: Prerequisites
+ options:
+ - label: I have bought a Commercial License
+ required: true
+ - label: I have written a descriptive issue title
+ required: true
+ - label: I have verified that I am running the latest version of ImageSharp
+ required: true
+ - label: I have verified if the problem exist in both `DEBUG` and `RELEASE` mode
+ required: true
+ - label: I have searched [open](https://github.com/SixLabors/ImageSharp/issues) and [closed](https://github.com/SixLabors/ImageSharp/issues?q=is%3Aissue+is%3Aclosed) issues to ensure it has not already been reported
+ required: true
- type: input
attributes:
label: ImageSharp version
diff --git a/.github/ISSUE_TEMPLATE/oss-bug-report.yml b/.github/ISSUE_TEMPLATE/oss-bug-report.yml
index 00138d511..a4e5619d4 100644
--- a/.github/ISSUE_TEMPLATE/oss-bug-report.yml
+++ b/.github/ISSUE_TEMPLATE/oss-bug-report.yml
@@ -2,6 +2,18 @@ name: "OSS : Bug Report"
description: Create a report to help us improve the project. OSS Issues are not guaranteed to be triaged.
labels: ["needs triage"]
body:
+- type: checkboxes
+ attributes:
+ label: Prerequisites
+ options:
+ - label: I have written a descriptive issue title
+ required: true
+ - label: I have verified that I am running the latest version of ImageSharp
+ required: true
+ - label: I have verified if the problem exist in both `DEBUG` and `RELEASE` mode
+ required: true
+ - label: I have searched [open](https://github.com/SixLabors/ImageSharp/issues) and [closed](https://github.com/SixLabors/ImageSharp/issues?q=is%3Aissue+is%3Aclosed) issues to ensure it has not already been reported
+ required: true
- type: input
attributes:
label: ImageSharp version
diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanScanDecoder.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanScanDecoder.cs
index cf2fd0290..e1faf93f4 100644
--- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanScanDecoder.cs
+++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanScanDecoder.cs
@@ -31,7 +31,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
///
/// Number of component in the current scan.
///
- private int componentsCount;
+ private int scanComponentCount;
///
/// The reset interval determined by RST markers.
@@ -112,11 +112,12 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
///
/// Decodes the entropy coded data.
///
- public void ParseEntropyCodedData(int componentCount)
+ /// Component count in the current scan.
+ public void ParseEntropyCodedData(int scanComponentCount)
{
this.cancellationToken.ThrowIfCancellationRequested();
- this.componentsCount = componentCount;
+ this.scanComponentCount = scanComponentCount;
this.scanBuffer = new HuffmanScanBuffer(this.stream);
@@ -148,7 +149,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
private void ParseBaselineData()
{
- if (this.componentsCount != 1)
+ if (this.scanComponentCount != 1)
{
this.ParseBaselineDataInterleaved();
this.spectralConverter.CommitConversion();
@@ -180,7 +181,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
{
// Scan an interleaved mcu... process components in order
int mcuCol = mcu % mcusPerLine;
- for (int k = 0; k < this.componentsCount; k++)
+ for (int k = 0; k < this.scanComponentCount; k++)
{
int order = this.frame.ComponentOrder[k];
JpegComponent component = this.components[order];
@@ -228,9 +229,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
// Convert from spectral to actual pixels via given converter
this.spectralConverter.ConvertStrideBaseline();
}
-
- // Stride conversion must be sealed for stride conversion approach
- this.spectralConverter.CommitConversion();
}
private void ParseBaselineDataNonInterleaved()
@@ -336,7 +334,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
}
// AC scans may have only one component.
- if (this.componentsCount != 1)
+ if (this.scanComponentCount != 1)
{
invalid = true;
}
@@ -368,7 +366,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
{
this.CheckProgressiveData();
- if (this.componentsCount == 1)
+ if (this.scanComponentCount == 1)
{
this.ParseProgressiveDataNonInterleaved();
}
@@ -393,7 +391,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
// Scan an interleaved mcu... process components in order
int mcuRow = mcu / mcusPerLine;
int mcuCol = mcu % mcusPerLine;
- for (int k = 0; k < this.componentsCount; k++)
+ for (int k = 0; k < this.scanComponentCount; k++)
{
int order = this.frame.ComponentOrder[k];
JpegComponent component = this.components[order];
diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/SpectralConverter{TPixel}.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/SpectralConverter{TPixel}.cs
index 40411ef28..430adeb21 100644
--- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/SpectralConverter{TPixel}.cs
+++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/SpectralConverter{TPixel}.cs
@@ -111,7 +111,10 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
this.pixelRowsPerStep = majorVerticalSamplingFactor * blockPixelHeight;
// pixel buffer for resulting image
- this.pixelBuffer = allocator.Allocate2D(frame.PixelWidth, frame.PixelHeight);
+ this.pixelBuffer = allocator.Allocate2D(
+ frame.PixelWidth,
+ frame.PixelHeight,
+ this.configuration.PreferContiguousImageBuffers);
this.paddedProxyPixelRow = allocator.Allocate(frame.PixelWidth + 3);
// component processors from spectral to Rgba32
diff --git a/src/ImageSharp/Image.Decode.cs b/src/ImageSharp/Image.Decode.cs
index ee340bf86..c892b82ba 100644
--- a/src/ImageSharp/Image.Decode.cs
+++ b/src/ImageSharp/Image.Decode.cs
@@ -37,8 +37,10 @@ namespace SixLabors.ImageSharp
ImageMetadata metadata)
where TPixel : unmanaged, IPixel
{
- Buffer2D uninitializedMemoryBuffer =
- configuration.MemoryAllocator.Allocate2D(width, height);
+ Buffer2D uninitializedMemoryBuffer = configuration.MemoryAllocator.Allocate2D(
+ width,
+ height,
+ configuration.PreferContiguousImageBuffers);
return new Image(configuration, uninitializedMemoryBuffer.FastMemoryGroup, width, height, metadata);
}
diff --git a/tests/ImageSharp.Tests/Image/LargeImageIntegrationTests.cs b/tests/ImageSharp.Tests/Image/LargeImageIntegrationTests.cs
index b2ee9d673..357d02be4 100644
--- a/tests/ImageSharp.Tests/Image/LargeImageIntegrationTests.cs
+++ b/tests/ImageSharp.Tests/Image/LargeImageIntegrationTests.cs
@@ -2,7 +2,10 @@
// Licensed under the Apache License, Version 2.0.
using System;
+using System.IO;
using Microsoft.DotNet.RemoteExecutor;
+using SixLabors.ImageSharp.Advanced;
+using SixLabors.ImageSharp.Formats;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing;
@@ -32,9 +35,40 @@ namespace SixLabors.ImageSharp.Tests
Configuration configuration = Configuration.Default.Clone();
configuration.PreferContiguousImageBuffers = true;
- using var image = new Image(configuration, 8192, 4096);
+ using var image = new Image(configuration, 2048, 2048);
Assert.True(image.DangerousTryGetSinglePixelMemory(out Memory mem));
- Assert.Equal(8192 * 4096, mem.Length);
+ Assert.Equal(2048 * 2048, mem.Length);
+ }
+ }
+
+ [Theory]
+ [InlineData("bmp")]
+ [InlineData("png")]
+ [InlineData("jpeg")]
+ [InlineData("gif")]
+ [InlineData("tiff")]
+ [InlineData("webp")]
+ public void PreferContiguousImageBuffers_LoadImage_BufferIsContiguous(string formatOuter)
+ {
+ // Run remotely to avoid large allocation in the test process:
+ RemoteExecutor.Invoke(RunTest, formatOuter).Dispose();
+
+ static void RunTest(string formatInner)
+ {
+ Configuration configuration = Configuration.Default.Clone();
+ configuration.PreferContiguousImageBuffers = true;
+ IImageEncoder encoder = configuration.ImageFormatsManager.FindEncoder(
+ configuration.ImageFormatsManager.FindFormatByFileExtension(formatInner));
+ string dir = TestEnvironment.CreateOutputDirectory(".Temp");
+ string path = Path.Combine(dir, $"{Guid.NewGuid().ToString()}.{formatInner}");
+ using (Image temp = new(2048, 2048))
+ {
+ temp.Save(path, encoder);
+ }
+
+ using var image = Image.Load(configuration, path);
+ File.Delete(path);
+ Assert.Equal(1, image.GetPixelMemoryGroup().Count);
}
}