diff --git a/.gitattributes b/.gitattributes
index 70ced69033..355b64dce1 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -87,7 +87,6 @@
*.eot binary
*.exe binary
*.otf binary
-*.pbm binary
*.pdf binary
*.ppt binary
*.pptx binary
@@ -95,7 +94,6 @@
*.snk binary
*.ttc binary
*.ttf binary
-*.wbmp binary
*.woff binary
*.woff2 binary
*.xls binary
@@ -126,3 +124,9 @@
*.dds filter=lfs diff=lfs merge=lfs -text
*.ktx filter=lfs diff=lfs merge=lfs -text
*.ktx2 filter=lfs diff=lfs merge=lfs -text
+*.pam filter=lfs diff=lfs merge=lfs -text
+*.pbm filter=lfs diff=lfs merge=lfs -text
+*.pgm filter=lfs diff=lfs merge=lfs -text
+*.ppm filter=lfs diff=lfs merge=lfs -text
+*.pnm filter=lfs diff=lfs merge=lfs -text
+*.wbmp filter=lfs diff=lfs merge=lfs -text
diff --git a/Directory.Build.props b/Directory.Build.props
index 3899ce939f..26b3cc5afc 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -13,6 +13,9 @@
$(MSBuildThisFileDirectory)
+
+
+ $(DefineConstants);DEBUG
@@ -30,5 +33,4 @@
true
-
diff --git a/shared-infrastructure b/shared-infrastructure
index a042aba176..59ce17f5a4 160000
--- a/shared-infrastructure
+++ b/shared-infrastructure
@@ -1 +1 @@
-Subproject commit a042aba176cdb840d800c6ed4cfe41a54fb7b1e3
+Subproject commit 59ce17f5a4e1f956811133f41add7638e74c2836
diff --git a/src/ImageSharp/Advanced/AdvancedImageExtensions.cs b/src/ImageSharp/Advanced/AdvancedImageExtensions.cs
index 54a773be05..829c6155db 100644
--- a/src/ImageSharp/Advanced/AdvancedImageExtensions.cs
+++ b/src/ImageSharp/Advanced/AdvancedImageExtensions.cs
@@ -143,7 +143,7 @@ public static IMemoryGroup GetPixelMemoryGroup(this ImageThe source.
/// The row.
/// The
- public static Memory GetPixelRowMemory(this ImageFrame source, int rowIndex)
+ public static Memory DangerousGetPixelRowMemory(this ImageFrame source, int rowIndex)
where TPixel : unmanaged, IPixel
{
Guard.NotNull(source, nameof(source));
@@ -161,7 +161,7 @@ public static Memory GetPixelRowMemory(this ImageFrame s
/// The source.
/// The row.
/// The
- public static Memory GetPixelRowMemory(this Image source, int rowIndex)
+ public static Memory DangerousGetPixelRowMemory(this Image source, int rowIndex)
where TPixel : unmanaged, IPixel
{
Guard.NotNull(source, nameof(source));
diff --git a/src/ImageSharp/Advanced/AotCompilerTools.cs b/src/ImageSharp/Advanced/AotCompilerTools.cs
index 3961cc6c57..b90a6ce3cd 100644
--- a/src/ImageSharp/Advanced/AotCompilerTools.cs
+++ b/src/ImageSharp/Advanced/AotCompilerTools.cs
@@ -529,7 +529,7 @@ private static void AotCompileDither()
private static void AotCompileMemoryManagers()
where TPixel : unmanaged, IPixel
{
- AotCompileMemoryManager();
+ AotCompileMemoryManager();
AotCompileMemoryManager();
}
diff --git a/src/ImageSharp/Common/Helpers/DebugGuard.cs b/src/ImageSharp/Common/Helpers/DebugGuard.cs
index f56cb37a81..f438ca9e24 100644
--- a/src/ImageSharp/Common/Helpers/DebugGuard.cs
+++ b/src/ImageSharp/Common/Helpers/DebugGuard.cs
@@ -26,6 +26,20 @@ public static void IsTrue(bool target, string message)
}
}
+ ///
+ /// Verifies whether a condition (indicating disposed state) is met, throwing an ObjectDisposedException if it's true.
+ ///
+ /// Whether the object is disposed.
+ /// The name of the object.
+ [Conditional("DEBUG")]
+ public static void NotDisposed(bool isDisposed, string objectName)
+ {
+ if (isDisposed)
+ {
+ throw new ObjectDisposedException(objectName);
+ }
+ }
+
///
/// Verifies, that the target span is of same size than the 'other' span.
///
diff --git a/src/ImageSharp/Common/Helpers/Shuffle/IComponentShuffle.cs b/src/ImageSharp/Common/Helpers/Shuffle/IComponentShuffle.cs
index 7687a5b95f..929b786921 100644
--- a/src/ImageSharp/Common/Helpers/Shuffle/IComponentShuffle.cs
+++ b/src/ImageSharp/Common/Helpers/Shuffle/IComponentShuffle.cs
@@ -28,6 +28,10 @@ internal interface IComponentShuffle
///
/// The source span of bytes.
/// The destination span of bytes.
+ ///
+ /// Implementation can assume that source.Length is less or equal than dest.Length.
+ /// Loops should iterate using source.Length.
+ ///
void RunFallbackShuffle(ReadOnlySpan source, Span dest);
}
diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.Shuffle.cs b/src/ImageSharp/Common/Helpers/SimdUtils.Shuffle.cs
index 07744566a3..abf9e9fed0 100644
--- a/src/ImageSharp/Common/Helpers/SimdUtils.Shuffle.cs
+++ b/src/ImageSharp/Common/Helpers/SimdUtils.Shuffle.cs
@@ -77,6 +77,7 @@ public static void Shuffle3(
TShuffle shuffle)
where TShuffle : struct, IShuffle3
{
+ // Source length should be smaller than dest length, and divisible by 3.
VerifyShuffle3SpanInput(source, dest);
#if SUPPORTS_RUNTIME_INTRINSICS
@@ -182,9 +183,9 @@ private static void VerifyShuffle3SpanInput(ReadOnlySpan source, Span d
where T : struct
{
DebugGuard.IsTrue(
- source.Length == dest.Length,
+ source.Length <= dest.Length,
nameof(source),
- "Input spans must be of same length!");
+ "Source should fit into dest!");
DebugGuard.IsTrue(
source.Length % 3 == 0,
diff --git a/src/ImageSharp/Configuration.cs b/src/ImageSharp/Configuration.cs
index ea9524827f..94584ff203 100644
--- a/src/ImageSharp/Configuration.cs
+++ b/src/ImageSharp/Configuration.cs
@@ -26,10 +26,11 @@ public sealed class Configuration
///
/// A lazily initialized configuration default instance.
///
- private static readonly Lazy Lazy = new Lazy(CreateDefaultInstance);
+ private static readonly Lazy Lazy = new(CreateDefaultInstance);
private const int DefaultStreamProcessingBufferSize = 8096;
private int streamProcessingBufferSize = DefaultStreamProcessingBufferSize;
private int maxDegreeOfParallelism = Environment.ProcessorCount;
+ private MemoryAllocator memoryAllocator = MemoryAllocator.Default;
///
/// Initializes a new instance of the class.
@@ -95,6 +96,14 @@ public int StreamProcessingBufferSize
}
}
+ ///
+ /// Gets or sets a value indicating whether to force image buffers to be contiguous whenever possible.
+ ///
+ ///
+ /// Contiguous allocations are not possible, if the image needs a buffer larger than .
+ ///
+ public bool PreferContiguousImageBuffers { get; set; }
+
///
/// Gets a set of properties for the Configuration.
///
@@ -117,9 +126,31 @@ public int StreamProcessingBufferSize
public ImageFormatManager ImageFormatsManager { get; set; } = new ImageFormatManager();
///
- /// Gets or sets the that is currently in use.
+ /// Gets or sets the that is currently in use.
+ /// Defaults to .
+ ///
+ /// Allocators are expensive, so it is strongly recommended to use only one busy instance per process.
+ /// In case you need to customize it, you can ensure this by changing
///
- public MemoryAllocator MemoryAllocator { get; set; } = ArrayPoolMemoryAllocator.CreateDefault();
+ ///
+ /// It's possible to reduce allocator footprint by assigning a custom instance created with
+ /// , but note that since the default pooling
+ /// allocators are expensive, it is strictly recommended to use a single process-wide allocator.
+ /// You can ensure this by altering the allocator of , or by implementing custom application logic that
+ /// manages allocator lifetime.
+ ///
+ /// If an allocator has to be dropped for some reason,
+ /// shall be invoked after disposing all associated instances.
+ ///
+ public MemoryAllocator MemoryAllocator
+ {
+ get => this.memoryAllocator;
+ set
+ {
+ Guard.NotNull(value, nameof(this.MemoryAllocator));
+ this.memoryAllocator = value;
+ }
+ }
///
/// Gets the maximum header size of all the formats.
@@ -165,7 +196,7 @@ public void Configure(IConfigurationModule configuration)
MaxDegreeOfParallelism = this.MaxDegreeOfParallelism,
StreamProcessingBufferSize = this.StreamProcessingBufferSize,
ImageFormatsManager = this.ImageFormatsManager,
- MemoryAllocator = this.MemoryAllocator,
+ memoryAllocator = this.memoryAllocator,
ImageOperationsProvider = this.ImageOperationsProvider,
ReadOrigin = this.ReadOrigin,
FileSystem = this.FileSystem,
diff --git a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs
index 8919befcb2..41adc1cfff 100644
--- a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs
+++ b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs
@@ -306,7 +306,7 @@ private void ReadRle(BmpCompression compression, Buffer2D pixels
int newY = Invert(y, height, inverted);
int rowStartIdx = y * width;
Span bufferRow = bufferSpan.Slice(rowStartIdx, width);
- Span pixelRow = pixels.GetRowSpan(newY);
+ Span pixelRow = pixels.DangerousGetRowSpan(newY);
bool rowHasUndefinedPixels = rowsWithUndefinedPixelsSpan[y];
if (rowHasUndefinedPixels)
@@ -377,7 +377,7 @@ private void ReadRle24(Buffer2D pixels, int width, int height, b
for (int y = 0; y < height; y++)
{
int newY = Invert(y, height, inverted);
- Span pixelRow = pixels.GetRowSpan(newY);
+ Span pixelRow = pixels.DangerousGetRowSpan(newY);
bool rowHasUndefinedPixels = rowsWithUndefinedPixelsSpan[y];
if (rowHasUndefinedPixels)
{
@@ -826,7 +826,7 @@ private void ReadRgbPalette(Buffer2D pixels, byte[] colors, int
int newY = Invert(y, height, inverted);
this.stream.Read(rowSpan);
int offset = 0;
- Span pixelRow = pixels.GetRowSpan(newY);
+ Span pixelRow = pixels.DangerousGetRowSpan(newY);
for (int x = 0; x < arrayWidth; x++)
{
@@ -878,7 +878,7 @@ private void ReadRgb16(Buffer2D pixels, int width, int height, b
{
this.stream.Read(bufferSpan);
int newY = Invert(y, height, inverted);
- Span pixelRow = pixels.GetRowSpan(newY);
+ Span pixelRow = pixels.DangerousGetRowSpan(newY);
int offset = 0;
for (int x = 0; x < width; x++)
@@ -933,7 +933,7 @@ private void ReadRgb24(Buffer2D pixels, int width, int height, b
{
this.stream.Read(rowSpan);
int newY = Invert(y, height, inverted);
- Span pixelSpan = pixels.GetRowSpan(newY);
+ Span pixelSpan = pixels.DangerousGetRowSpan(newY);
PixelOperations.Instance.FromBgr24Bytes(
this.Configuration,
rowSpan,
@@ -961,7 +961,7 @@ private void ReadRgb32Fast(Buffer2D pixels, int width, int heigh
{
this.stream.Read(rowSpan);
int newY = Invert(y, height, inverted);
- Span pixelSpan = pixels.GetRowSpan(newY);
+ Span pixelSpan = pixels.DangerousGetRowSpan(newY);
PixelOperations.Instance.FromBgra32Bytes(
this.Configuration,
rowSpan,
@@ -1031,7 +1031,7 @@ private void ReadRgb32Slow(Buffer2D pixels, int width, int heigh
this.stream.Read(rowSpan);
int newY = Invert(y, height, inverted);
- Span pixelSpan = pixels.GetRowSpan(newY);
+ Span pixelSpan = pixels.DangerousGetRowSpan(newY);
PixelOperations.Instance.FromBgra32Bytes(
this.Configuration,
@@ -1054,7 +1054,7 @@ private void ReadRgb32Slow(Buffer2D pixels, int width, int heigh
width);
int newY = Invert(y, height, inverted);
- Span pixelSpan = pixels.GetRowSpan(newY);
+ Span pixelSpan = pixels.DangerousGetRowSpan(newY);
for (int x = 0; x < width; x++)
{
@@ -1109,7 +1109,7 @@ private void ReadRgb32BitFields(Buffer2D pixels, int width, int
{
this.stream.Read(bufferSpan);
int newY = Invert(y, height, inverted);
- Span pixelRow = pixels.GetRowSpan(newY);
+ Span pixelRow = pixels.DangerousGetRowSpan(newY);
int offset = 0;
for (int x = 0; x < width; x++)
diff --git a/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs b/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs
index c6ca5b09d2..6384074df3 100644
--- a/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs
+++ b/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs
@@ -274,7 +274,7 @@ private void Write32Bit(Stream stream, Buffer2D pixels)
for (int y = pixels.Height - 1; y >= 0; y--)
{
- Span pixelSpan = pixels.GetRowSpan(y);
+ Span pixelSpan = pixels.DangerousGetRowSpan(y);
PixelOperations.Instance.ToBgra32Bytes(
this.configuration,
pixelSpan,
@@ -300,7 +300,7 @@ private void Write24Bit(Stream stream, Buffer2D pixels)
for (int y = pixels.Height - 1; y >= 0; y--)
{
- Span pixelSpan = pixels.GetRowSpan(y);
+ Span pixelSpan = pixels.DangerousGetRowSpan(y);
PixelOperations.Instance.ToBgr24Bytes(
this.configuration,
pixelSpan,
@@ -326,7 +326,7 @@ private void Write16Bit(Stream stream, Buffer2D pixels)
for (int y = pixels.Height - 1; y >= 0; y--)
{
- Span pixelSpan = pixels.GetRowSpan(y);
+ Span pixelSpan = pixels.DangerousGetRowSpan(y);
PixelOperations.Instance.ToBgra5551Bytes(
this.configuration,
@@ -379,7 +379,7 @@ private void Write8BitColor(Stream stream, ImageFrame image, Spa
for (int y = image.Height - 1; y >= 0; y--)
{
- ReadOnlySpan pixelSpan = quantized.GetPixelRowSpan(y);
+ ReadOnlySpan pixelSpan = quantized.DangerousGetRowSpan(y);
stream.Write(pixelSpan);
for (int i = 0; i < this.padding; i++)
@@ -413,10 +413,10 @@ private void Write8BitGray(Stream stream, ImageFrame image, Span
}
stream.Write(colorPalette);
-
+ Buffer2D imageBuffer = image.PixelBuffer;
for (int y = image.Height - 1; y >= 0; y--)
{
- ReadOnlySpan inputPixelRow = image.GetPixelRowSpan(y);
+ ReadOnlySpan inputPixelRow = imageBuffer.DangerousGetRowSpan(y);
ReadOnlySpan outputPixelRow = MemoryMarshal.AsBytes(inputPixelRow);
stream.Write(outputPixelRow);
@@ -447,11 +447,11 @@ private void Write4BitColor(Stream stream, ImageFrame image)
ReadOnlySpan quantizedColorPalette = quantized.Palette.Span;
this.WriteColorPalette(stream, quantizedColorPalette, colorPalette);
- ReadOnlySpan pixelRowSpan = quantized.GetPixelRowSpan(0);
+ ReadOnlySpan pixelRowSpan = quantized.DangerousGetRowSpan(0);
int rowPadding = pixelRowSpan.Length % 2 != 0 ? this.padding - 1 : this.padding;
for (int y = image.Height - 1; y >= 0; y--)
{
- pixelRowSpan = quantized.GetPixelRowSpan(y);
+ pixelRowSpan = quantized.DangerousGetRowSpan(y);
int endIdx = pixelRowSpan.Length % 2 == 0 ? pixelRowSpan.Length : pixelRowSpan.Length - 1;
for (int i = 0; i < endIdx; i += 2)
@@ -491,11 +491,11 @@ private void Write1BitColor(Stream stream, ImageFrame image)
ReadOnlySpan quantizedColorPalette = quantized.Palette.Span;
this.WriteColorPalette(stream, quantizedColorPalette, colorPalette);
- ReadOnlySpan quantizedPixelRow = quantized.GetPixelRowSpan(0);
+ ReadOnlySpan quantizedPixelRow = quantized.DangerousGetRowSpan(0);
int rowPadding = quantizedPixelRow.Length % 8 != 0 ? this.padding - 1 : this.padding;
for (int y = image.Height - 1; y >= 0; y--)
{
- quantizedPixelRow = quantized.GetPixelRowSpan(y);
+ quantizedPixelRow = quantized.DangerousGetRowSpan(y);
int endIdx = quantizedPixelRow.Length % 8 == 0 ? quantizedPixelRow.Length : quantizedPixelRow.Length - 8;
for (int i = 0; i < endIdx; i += 8)
diff --git a/src/ImageSharp/Formats/Gif/GifDecoderCore.cs b/src/ImageSharp/Formats/Gif/GifDecoderCore.cs
index 482a761530..3e33a6e379 100644
--- a/src/ImageSharp/Formats/Gif/GifDecoderCore.cs
+++ b/src/ImageSharp/Formats/Gif/GifDecoderCore.cs
@@ -445,7 +445,7 @@ private void ReadFrameColors(ref Image image, ref ImageFrame(ref Image image, ref ImageFrame pixels)
int y = 0;
int x = 0;
int rowMax = width;
- ref byte pixelsRowRef = ref MemoryMarshal.GetReference(pixels.GetRowSpan(y));
+ ref byte pixelsRowRef = ref MemoryMarshal.GetReference(pixels.DangerousGetRowSpan(y));
while (xyz < length)
{
// Reset row reference.
if (xyz == rowMax)
{
x = 0;
- pixelsRowRef = ref MemoryMarshal.GetReference(pixels.GetRowSpan(++y));
+ pixelsRowRef = ref MemoryMarshal.GetReference(pixels.DangerousGetRowSpan(++y));
rowMax = (y * width) + width;
}
diff --git a/src/ImageSharp/Formats/Gif/LzwEncoder.cs b/src/ImageSharp/Formats/Gif/LzwEncoder.cs
index e9fb7ab00b..c52e34f963 100644
--- a/src/ImageSharp/Formats/Gif/LzwEncoder.cs
+++ b/src/ImageSharp/Formats/Gif/LzwEncoder.cs
@@ -275,7 +275,7 @@ private void Compress(Buffer2D indexedPixels, int initialBits, Stream stre
for (int y = 0; y < indexedPixels.Height; y++)
{
- ref byte rowSpanRef = ref MemoryMarshal.GetReference(indexedPixels.GetRowSpan(y));
+ ref byte rowSpanRef = ref MemoryMarshal.GetReference(indexedPixels.DangerousGetRowSpan(y));
int offsetX = y == 0 ? 1 : 0;
for (int x = offsetX; x < indexedPixels.Width; x++)
diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.cs
index dad46861e2..79eedf2f7d 100644
--- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.cs
+++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.cs
@@ -223,12 +223,12 @@ public ComponentValues(IReadOnlyList> componentBuffers, int row)
{
this.ComponentCount = componentBuffers.Count;
- this.Component0 = componentBuffers[0].GetRowSpan(row);
+ this.Component0 = componentBuffers[0].DangerousGetRowSpan(row);
// In case of grayscale, Component1 and Component2 point to Component0 memory area
- this.Component1 = this.ComponentCount > 1 ? componentBuffers[1].GetRowSpan(row) : this.Component0;
- this.Component2 = this.ComponentCount > 2 ? componentBuffers[2].GetRowSpan(row) : this.Component0;
- this.Component3 = this.ComponentCount > 3 ? componentBuffers[3].GetRowSpan(row) : Span.Empty;
+ this.Component1 = this.ComponentCount > 1 ? componentBuffers[1].DangerousGetRowSpan(row) : this.Component0;
+ this.Component2 = this.ComponentCount > 2 ? componentBuffers[2].DangerousGetRowSpan(row) : this.Component0;
+ this.Component3 = this.ComponentCount > 3 ? componentBuffers[3].DangerousGetRowSpan(row) : Span.Empty;
}
internal ComponentValues(
diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanScanDecoder.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanScanDecoder.cs
index 6f104351c8..ce5e5110b6 100644
--- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanScanDecoder.cs
+++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanScanDecoder.cs
@@ -203,7 +203,7 @@ private void ParseBaselineDataInterleaved()
// by the basic H and V specified for the component
for (int y = 0; y < v; y++)
{
- Span blockSpan = component.SpectralBlocks.GetRowSpan(y);
+ Span blockSpan = component.SpectralBlocks.DangerousGetRowSpan(y);
ref Block8x8 blockRef = ref MemoryMarshal.GetReference(blockSpan);
for (int x = 0; x < h; x++)
@@ -254,7 +254,7 @@ private void ParseBaselineDataNonInterleaved()
for (int j = 0; j < h; j++)
{
this.cancellationToken.ThrowIfCancellationRequested();
- Span blockSpan = component.SpectralBlocks.GetRowSpan(j);
+ Span blockSpan = component.SpectralBlocks.DangerousGetRowSpan(j);
ref Block8x8 blockRef = ref MemoryMarshal.GetReference(blockSpan);
for (int i = 0; i < w; i++)
@@ -377,7 +377,7 @@ private void ParseProgressiveDataInterleaved()
for (int y = 0; y < v; y++)
{
int blockRow = (mcuRow * v) + y;
- Span blockSpan = component.SpectralBlocks.GetRowSpan(blockRow);
+ Span blockSpan = component.SpectralBlocks.DangerousGetRowSpan(blockRow);
ref Block8x8 blockRef = ref MemoryMarshal.GetReference(blockSpan);
for (int x = 0; x < h; x++)
@@ -422,7 +422,7 @@ private void ParseProgressiveDataNonInterleaved()
{
this.cancellationToken.ThrowIfCancellationRequested();
- Span blockSpan = component.SpectralBlocks.GetRowSpan(j);
+ Span blockSpan = component.SpectralBlocks.DangerousGetRowSpan(j);
ref Block8x8 blockRef = ref MemoryMarshal.GetReference(blockSpan);
for (int i = 0; i < w; i++)
@@ -450,7 +450,7 @@ ref Unsafe.Add(ref blockRef, i),
{
this.cancellationToken.ThrowIfCancellationRequested();
- Span blockSpan = component.SpectralBlocks.GetRowSpan(j);
+ Span blockSpan = component.SpectralBlocks.DangerousGetRowSpan(j);
ref Block8x8 blockRef = ref MemoryMarshal.GetReference(blockSpan);
for (int i = 0; i < w; i++)
diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegComponentPostProcessor.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegComponentPostProcessor.cs
index 3e04e80b7a..c3bf1cbdd5 100644
--- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegComponentPostProcessor.cs
+++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegComponentPostProcessor.cs
@@ -84,8 +84,8 @@ public void CopyBlocksToColorBuffer(int spectralStep)
{
int yBuffer = y * this.blockAreaSize.Height;
- Span colorBufferRow = this.ColorBuffer.GetRowSpan(yBuffer);
- Span blockRow = spectralBuffer.GetRowSpan(yBlockStart + y);
+ Span colorBufferRow = this.ColorBuffer.DangerousGetRowSpan(yBuffer);
+ Span blockRow = spectralBuffer.DangerousGetRowSpan(yBlockStart + y);
for (int xBlock = 0; xBlock < spectralBuffer.Width; xBlock++)
{
@@ -119,11 +119,11 @@ public void ClearSpectralBuffers()
Buffer2D spectralBlocks = this.component.SpectralBlocks;
for (int i = 0; i < spectralBlocks.Height; i++)
{
- spectralBlocks.GetRowSpan(i).Clear();
+ spectralBlocks.DangerousGetRowSpan(i).Clear();
}
}
public Span GetColorBufferRowSpan(int row) =>
- this.ColorBuffer.GetRowSpan(row);
+ this.ColorBuffer.DangerousGetRowSpan(row);
}
}
diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/SpectralConverter{TPixel}.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/SpectralConverter{TPixel}.cs
index 0003437e74..5edcf565c2 100644
--- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/SpectralConverter{TPixel}.cs
+++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/SpectralConverter{TPixel}.cs
@@ -187,7 +187,7 @@ private void ConvertStride(int spectralStep)
{
Span proxyRow = this.paddedProxyPixelRow.GetSpan();
PixelOperations.Instance.PackFromRgbPlanes(this.configuration, r, g, b, proxyRow);
- proxyRow.Slice(0, width).CopyTo(this.pixelBuffer.GetRowSpan(yy));
+ proxyRow.Slice(0, width).CopyTo(this.pixelBuffer.DangerousGetRowSpan(yy));
}
}
diff --git a/src/ImageSharp/Formats/Jpeg/Components/RowOctet.cs b/src/ImageSharp/Formats/Jpeg/Components/RowOctet.cs
index 16d24cf814..d4a4c1cf45 100644
--- a/src/ImageSharp/Formats/Jpeg/Components/RowOctet.cs
+++ b/src/ImageSharp/Formats/Jpeg/Components/RowOctet.cs
@@ -86,7 +86,7 @@ public void Update(Buffer2D buffer, int startY)
int i = 0;
while (y < yEnd)
{
- this[i++] = buffer.GetRowSpan(y++);
+ this[i++] = buffer.DangerousGetRowSpan(y++);
}
}
diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs
index cf3cd7eb14..da8481c26c 100644
--- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs
+++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs
@@ -565,6 +565,7 @@ private void DecodeInterlacedPixelData(DeflateStream compressedStream, I
{
int pass = 0;
int width = this.header.Width;
+ Buffer2D imageBuffer = image.PixelBuffer;
while (true)
{
int numColumns = Adam7.ComputeColumns(width, pass);
@@ -623,7 +624,7 @@ private void DecodeInterlacedPixelData(DeflateStream compressedStream, I
break;
}
- Span rowSpan = image.GetPixelRowSpan(this.currentRow);
+ Span rowSpan = imageBuffer.DangerousGetRowSpan(this.currentRow);
this.ProcessInterlacedDefilteredScanline(this.scanline.GetSpan(), rowSpan, pngMetadata, Adam7.FirstColumn[pass], Adam7.ColumnIncrement[pass]);
this.SwapScanlineBuffers();
@@ -656,7 +657,7 @@ private void DecodeInterlacedPixelData(DeflateStream compressedStream, I
private void ProcessDefilteredScanline(ReadOnlySpan defilteredScanline, ImageFrame pixels, PngMetadata pngMetadata)
where TPixel : unmanaged, IPixel
{
- Span rowSpan = pixels.GetPixelRowSpan(this.currentRow);
+ Span rowSpan = pixels.PixelBuffer.DangerousGetRowSpan(this.currentRow);
// Trim the first marker byte from the buffer
ReadOnlySpan trimmed = defilteredScanline.Slice(1, defilteredScanline.Length - 1);
diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs
index f10db7a6c0..5e067aba57 100644
--- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs
+++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs
@@ -163,23 +163,25 @@ public void Dispose()
/// The type of the pixel.
/// The cloned image where the transparent pixels will be changed.
private static void ClearTransparentPixels(Image image)
- where TPixel : unmanaged, IPixel
- {
- Rgba32 rgba32 = default;
- for (int y = 0; y < image.Height; y++)
+ where TPixel : unmanaged, IPixel =>
+ image.ProcessPixelRows(accessor =>
{
- Span span = image.GetPixelRowSpan(y);
- for (int x = 0; x < image.Width; x++)
+ Rgba32 rgba32 = default;
+ Rgba32 transparent = Color.Transparent;
+ for (int y = 0; y < accessor.Height; y++)
{
- span[x].ToRgba32(ref rgba32);
-
- if (rgba32.A == 0)
+ Span span = accessor.GetRowSpan(y);
+ for (int x = 0; x < accessor.Width; x++)
{
- span[x].FromRgba32(Color.Transparent);
+ span[x].ToRgba32(ref rgba32);
+
+ if (rgba32.A == 0)
+ {
+ span[x].FromRgba32(transparent);
+ }
}
}
- }
- }
+ });
///
/// Creates the quantized image and sets calculates and sets the bit depth.
@@ -391,11 +393,11 @@ private void CollectPixelBytes(ReadOnlySpan rowSpan, IndexedImag
if (this.bitDepth < 8)
{
- PngEncoderHelpers.ScaleDownFrom8BitArray(quantized.GetPixelRowSpan(row), this.currentScanline.GetSpan(), this.bitDepth);
+ PngEncoderHelpers.ScaleDownFrom8BitArray(quantized.DangerousGetRowSpan(row), this.currentScanline.GetSpan(), this.bitDepth);
}
else
{
- quantized.GetPixelRowSpan(row).CopyTo(this.currentScanline.GetSpan());
+ quantized.DangerousGetRowSpan(row).CopyTo(this.currentScanline.GetSpan());
}
break;
@@ -914,27 +916,31 @@ private void EncodePixels(Image pixels, IndexedImageFrame filterBuffer = this.memoryAllocator.Allocate(filterLength, AllocationOptions.Clean);
using IMemoryOwner attemptBuffer = this.memoryAllocator.Allocate(filterLength, AllocationOptions.Clean);
- Span filter = filterBuffer.GetSpan();
- Span attempt = attemptBuffer.GetSpan();
- for (int y = 0; y < this.height; y++)
+ pixels.ProcessPixelRows(accessor =>
{
- this.CollectAndFilterPixelRow(pixels.GetPixelRowSpan(y), ref filter, ref attempt, quantized, y);
- deflateStream.Write(filter);
- this.SwapScanlineBuffers();
- }
+ Span filter = filterBuffer.GetSpan();
+ Span attempt = attemptBuffer.GetSpan();
+ for (int y = 0; y < this.height; y++)
+ {
+ this.CollectAndFilterPixelRow(accessor.GetRowSpan(y), ref filter, ref attempt, quantized, y);
+ deflateStream.Write(filter);
+ this.SwapScanlineBuffers();
+ }
+ });
}
///
/// Interlaced encoding the pixels.
///
/// The type of the pixel.
- /// The pixels.
+ /// The image.
/// The deflate stream.
- private void EncodeAdam7Pixels(Image pixels, ZlibDeflateStream deflateStream)
+ private void EncodeAdam7Pixels(Image image, ZlibDeflateStream deflateStream)
where TPixel : unmanaged, IPixel
{
- int width = pixels.Width;
- int height = pixels.Height;
+ int width = image.Width;
+ int height = image.Height;
+ Buffer2D pixelBuffer = image.Frames.RootFrame.PixelBuffer;
for (int pass = 0; pass < 7; pass++)
{
int startRow = Adam7.FirstRow[pass];
@@ -959,7 +965,7 @@ private void EncodeAdam7Pixels(Image pixels, ZlibDeflateStream d
for (int row = startRow; row < height; row += Adam7.RowIncrement[pass])
{
// Collect pixel data
- Span srcRow = pixels.GetPixelRowSpan(row);
+ Span srcRow = pixelBuffer.DangerousGetRowSpan(row);
for (int col = startCol, i = 0; col < width; col += Adam7.ColumnIncrement[pass])
{
block[i++] = srcRow[col];
@@ -1014,7 +1020,7 @@ private void EncodeAdam7IndexedPixels(IndexedImageFrame quantize
row += Adam7.RowIncrement[pass])
{
// Collect data
- ReadOnlySpan srcRow = quantized.GetPixelRowSpan(row);
+ ReadOnlySpan srcRow = quantized.DangerousGetRowSpan(row);
for (int col = startCol, i = 0;
col < width;
col += Adam7.ColumnIncrement[pass])
diff --git a/src/ImageSharp/Formats/Tga/TgaDecoderCore.cs b/src/ImageSharp/Formats/Tga/TgaDecoderCore.cs
index 8f97861400..d101ccd94a 100644
--- a/src/ImageSharp/Formats/Tga/TgaDecoderCore.cs
+++ b/src/ImageSharp/Formats/Tga/TgaDecoderCore.cs
@@ -234,7 +234,7 @@ private void ReadPaletted(int width, int height, Buffer2D pixels
for (int y = 0; y < height; y++)
{
int newY = InvertY(y, height, origin);
- Span pixelRow = pixels.GetRowSpan(newY);
+ Span pixelRow = pixels.DangerousGetRowSpan(newY);
switch (colorMapPixelSizeInBytes)
{
@@ -318,7 +318,7 @@ private void ReadPalettedRle(int width, int height, Buffer2D pix
for (int y = 0; y < height; y++)
{
int newY = InvertY(y, height, origin);
- Span pixelRow = pixels.GetRowSpan(newY);
+ Span pixelRow = pixels.DangerousGetRowSpan(newY);
int rowStartIdx = y * width * bytesPerPixel;
for (int x = 0; x < width; x++)
{
@@ -364,7 +364,7 @@ private void ReadMonoChrome(int width, int height, Buffer2D pixe
for (int y = 0; y < height; y++)
{
int newY = InvertY(y, height, origin);
- Span pixelSpan = pixels.GetRowSpan(newY);
+ Span pixelSpan = pixels.DangerousGetRowSpan(newY);
for (int x = width - 1; x >= 0; x--)
{
this.ReadL8Pixel(color, x, pixelSpan);
@@ -412,7 +412,7 @@ private void ReadBgra16(int width, int height, Buffer2D pixels,
for (int y = 0; y < height; y++)
{
int newY = InvertY(y, height, origin);
- Span pixelSpan = pixels.GetRowSpan(newY);
+ Span pixelSpan = pixels.DangerousGetRowSpan(newY);
if (invertX)
{
@@ -479,7 +479,7 @@ private void ReadBgr24(int width, int height, Buffer2D pixels, T
for (int y = 0; y < height; y++)
{
int newY = InvertY(y, height, origin);
- Span pixelSpan = pixels.GetRowSpan(newY);
+ Span pixelSpan = pixels.DangerousGetRowSpan(newY);
for (int x = width - 1; x >= 0; x--)
{
this.ReadBgr24Pixel(color, x, pixelSpan);
@@ -548,7 +548,7 @@ private void ReadBgra32(int width, int height, Buffer2D pixels,
for (int y = 0; y < height; y++)
{
int newY = InvertY(y, height, origin);
- Span pixelRow = pixels.GetRowSpan(newY);
+ Span pixelRow = pixels.DangerousGetRowSpan(newY);
if (invertX)
{
for (int x = width - 1; x >= 0; x--)
@@ -587,7 +587,7 @@ private void ReadRle(int width, int height, Buffer2D pixels, int
for (int y = 0; y < height; y++)
{
int newY = InvertY(y, height, origin);
- Span pixelRow = pixels.GetRowSpan(newY);
+ Span pixelRow = pixels.DangerousGetRowSpan(newY);
int rowStartIdx = y * width * bytesPerPixel;
for (int x = 0; x < width; x++)
{
@@ -654,7 +654,7 @@ private void ReadL8Row(int width, Buffer2D pixels, Span ro
where TPixel : unmanaged, IPixel
{
this.currentStream.Read(row);
- Span pixelSpan = pixels.GetRowSpan(y);
+ Span pixelSpan = pixels.DangerousGetRowSpan(y);
PixelOperations.Instance.FromL8Bytes(this.Configuration, row, pixelSpan, width);
}
@@ -681,7 +681,7 @@ private void ReadBgr24Row(int width, Buffer2D pixels, Span
where TPixel : unmanaged, IPixel
{
this.currentStream.Read(row);
- Span pixelSpan = pixels.GetRowSpan(y);
+ Span pixelSpan = pixels.DangerousGetRowSpan(y);
PixelOperations.Instance.FromBgr24Bytes(this.Configuration, row, pixelSpan, width);
}
@@ -700,7 +700,7 @@ private void ReadBgra32Row(int width, Buffer2D pixels, Span
{
this.currentStream.Read(row);
- Span pixelSpan = pixels.GetRowSpan(y);
+ Span pixelSpan = pixels.DangerousGetRowSpan(y);
PixelOperations.Instance.FromBgra32Bytes(this.Configuration, row, pixelSpan, width);
}
diff --git a/src/ImageSharp/Formats/Tga/TgaEncoderCore.cs b/src/ImageSharp/Formats/Tga/TgaEncoderCore.cs
index 4bf4ca60a1..1a1260a58e 100644
--- a/src/ImageSharp/Formats/Tga/TgaEncoderCore.cs
+++ b/src/ImageSharp/Formats/Tga/TgaEncoderCore.cs
@@ -276,7 +276,7 @@ private void Write8Bit(Stream stream, Buffer2D pixels)
for (int y = pixels.Height - 1; y >= 0; y--)
{
- Span pixelSpan = pixels.GetRowSpan(y);
+ Span pixelSpan = pixels.DangerousGetRowSpan(y);
PixelOperations.Instance.ToL8Bytes(
this.configuration,
pixelSpan,
@@ -300,7 +300,7 @@ private void Write16Bit(Stream stream, Buffer2D pixels)
for (int y = pixels.Height - 1; y >= 0; y--)
{
- Span pixelSpan = pixels.GetRowSpan(y);
+ Span pixelSpan = pixels.DangerousGetRowSpan(y);
PixelOperations.Instance.ToBgra5551Bytes(
this.configuration,
pixelSpan,
@@ -324,7 +324,7 @@ private void Write24Bit(Stream stream, Buffer2D pixels)
for (int y = pixels.Height - 1; y >= 0; y--)
{
- Span pixelSpan = pixels.GetRowSpan(y);
+ Span pixelSpan = pixels.DangerousGetRowSpan(y);
PixelOperations.Instance.ToBgr24Bytes(
this.configuration,
pixelSpan,
@@ -348,7 +348,7 @@ private void Write32Bit(Stream stream, Buffer2D pixels)
for (int y = pixels.Height - 1; y >= 0; y--)
{
- Span pixelSpan = pixels.GetRowSpan(y);
+ Span pixelSpan = pixels.DangerousGetRowSpan(y);
PixelOperations.Instance.ToBgra32Bytes(
this.configuration,
pixelSpan,
diff --git a/src/ImageSharp/Formats/Tiff/Compression/Decompressors/JpegTiffCompression.cs b/src/ImageSharp/Formats/Tiff/Compression/Decompressors/JpegTiffCompression.cs
index c64fc8ad12..ce7820ccf9 100644
--- a/src/ImageSharp/Formats/Tiff/Compression/Decompressors/JpegTiffCompression.cs
+++ b/src/ImageSharp/Formats/Tiff/Compression/Decompressors/JpegTiffCompression.cs
@@ -79,7 +79,7 @@ private static void CopyImageBytesToBuffer(Span