From 1a69191d4c93d077ba2041acfa180726f4ab358d Mon Sep 17 00:00:00 2001 From: ikkyu Date: Thu, 20 Feb 2025 16:21:02 +0700 Subject: [PATCH 1/2] [DW-30] optimize ExtractAlphaData use array and index to increase speed --- .../IronSoftware.Drawing.Common/AnyBitmap.cs | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/IronSoftware.Drawing/IronSoftware.Drawing.Common/AnyBitmap.cs b/IronSoftware.Drawing/IronSoftware.Drawing.Common/AnyBitmap.cs index 36294a4..9fa1dc7 100644 --- a/IronSoftware.Drawing/IronSoftware.Drawing.Common/AnyBitmap.cs +++ b/IronSoftware.Drawing/IronSoftware.Drawing.Common/AnyBitmap.cs @@ -828,7 +828,8 @@ public byte[] ExtractAlphaData() { if (BitsPerPixel == 32) { - var alpha = new List(Image.Width * Image.Height); + var alpha = new byte[Image.Width * Image.Height]; + int alphaIndex = 0; using var rgbaImage = Image is Image image ? image : Image.CloneAs(); @@ -836,12 +837,16 @@ public byte[] ExtractAlphaData() { for (int y = 0; y < accessor.Height; y++) { - Span pixelRow = accessor.GetRowSpan(y); - - for (int x = 0; x < pixelRow.Length; x++) + // Get the row as a span of Rgba32. + Span pixelRow = accessor.GetRowSpan(y); + // Interpret the row as a span of bytes. + Span rowBytes = MemoryMarshal.AsBytes(pixelRow); + + // Each pixel is 4 bytes: R, G, B, A. + // The alpha channel is the fourth byte (index 3, 7, 11, ...). + for (int i = 3; i < rowBytes.Length; i += 4) { - SixLabors.ImageSharp.PixelFormats.Rgba32 pixel = pixelRow[x]; - alpha.Add(pixel.A); + alpha[alphaIndex++] = rowBytes[i]; } } }); From 3872ae2417b2e87d3d4c00146f962aafb6238bd2 Mon Sep 17 00:00:00 2001 From: ikkyu Date: Thu, 20 Feb 2025 16:21:44 +0700 Subject: [PATCH 2/2] [DW-30] optimize PrepareByteArray use BlockCopy for faster copy --- .../IronSoftware.Drawing.Common/AnyBitmap.cs | 37 +++++++++++++------ 1 file changed, 26 insertions(+), 11 deletions(-) diff --git a/IronSoftware.Drawing/IronSoftware.Drawing.Common/AnyBitmap.cs b/IronSoftware.Drawing/IronSoftware.Drawing.Common/AnyBitmap.cs index 9fa1dc7..2fda921 100644 --- a/IronSoftware.Drawing/IronSoftware.Drawing.Common/AnyBitmap.cs +++ b/IronSoftware.Drawing/IronSoftware.Drawing.Common/AnyBitmap.cs @@ -2337,20 +2337,35 @@ private bool IsThumbnail(Tiff tiff) private ReadOnlySpan PrepareByteArray(Image bmp, int[] raster, int width, int height) { - byte[] bits = new byte[GetStride(bmp) * height]; + int stride = GetStride(bmp); + byte[] bits = new byte[stride * height]; - for (int y = 0; y < height; y++) + // If no extra padding exists, copy entire rows at once. + if (stride == width * 4 && true) { - int rasterOffset = y * width; - int bitsOffset = (height - y - 1) * GetStride(bmp); - - for (int x = 0; x < width; x++) + int bytesPerRow = stride; + for (int y = 0; y < height; y++) { - int rgba = raster[rasterOffset++]; - bits[bitsOffset++] = (byte)(rgba & 0xff); // R - bits[bitsOffset++] = (byte)((rgba >> 8) & 0xff); // G - bits[bitsOffset++] = (byte)((rgba >> 16) & 0xff); // B - bits[bitsOffset++] = (byte)((rgba >> 24) & 0xff); // A + int srcByteIndex = y * bytesPerRow; + int destByteIndex = (height - y - 1) * bytesPerRow; + Buffer.BlockCopy(raster, srcByteIndex, bits, destByteIndex, bytesPerRow); + } + } + else + { + // Fallback to per-pixel processing if stride includes padding. + for (int y = 0; y < height; y++) + { + int rasterOffset = y * width; + int bitsOffset = (height - y - 1) * stride; + for (int x = 0; x < width; x++) + { + int rgba = raster[rasterOffset++]; + bits[bitsOffset++] = (byte)(rgba & 0xff); // R + bits[bitsOffset++] = (byte)((rgba >> 8) & 0xff); // G + bits[bitsOffset++] = (byte)((rgba >> 16) & 0xff); // B + bits[bitsOffset++] = (byte)((rgba >> 24) & 0xff); // A + } } }