// Copyright (c) Six Labors. // Licensed under the Six Labors Split License. using System.Buffers; using System.Drawing; using System.Drawing.Imaging; using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs; /// /// Provides methods to convert to/from System.Drawing bitmaps. /// public static class SystemDrawingBridge { /// /// Returns an image from the given System.Drawing bitmap. /// /// The pixel format. /// The input bitmap. /// Thrown if the image pixel format is not of type internal static unsafe Image From32bppArgbSystemDrawingBitmap(Bitmap bmp) where TPixel : unmanaged, IPixel { int w = bmp.Width; int h = bmp.Height; var fullRect = new System.Drawing.Rectangle(0, 0, w, h); if (bmp.PixelFormat != PixelFormat.Format32bppArgb) { throw new ArgumentException( $"{nameof(From32bppArgbSystemDrawingBitmap)} : pixel format should be {PixelFormat.Format32bppArgb}!", nameof(bmp)); } BitmapData data = bmp.LockBits(fullRect, ImageLockMode.ReadWrite, bmp.PixelFormat); var image = new Image(w, h); try { byte* sourcePtrBase = (byte*)data.Scan0; long sourceRowByteCount = data.Stride; long destRowByteCount = w * sizeof(Bgra32); Configuration configuration = image.GetConfiguration(); image.ProcessPixelRows(accessor => { using IMemoryOwner workBuffer = Configuration.Default.MemoryAllocator.Allocate(w); fixed (Bgra32* destPtr = &workBuffer.GetReference()) { for (int y = 0; y < h; y++) { Span row = accessor.GetRowSpan(y); byte* sourcePtr = sourcePtrBase + (data.Stride * y); Buffer.MemoryCopy(sourcePtr, destPtr, destRowByteCount, sourceRowByteCount); PixelOperations.Instance.FromBgra32( configuration, workBuffer.GetSpan().Slice(0, w), row); } } }); } finally { bmp.UnlockBits(data); } return image; } /// /// Returns an image from the given System.Drawing bitmap. /// /// The pixel format. /// The input bitmap. /// Thrown if the image pixel format is not of type internal static unsafe Image From24bppRgbSystemDrawingBitmap(Bitmap bmp) where TPixel : unmanaged, IPixel { int w = bmp.Width; int h = bmp.Height; var fullRect = new System.Drawing.Rectangle(0, 0, w, h); if (bmp.PixelFormat != PixelFormat.Format24bppRgb) { throw new ArgumentException( $"{nameof(From24bppRgbSystemDrawingBitmap)}: pixel format should be {PixelFormat.Format24bppRgb}!", nameof(bmp)); } BitmapData data = bmp.LockBits(fullRect, ImageLockMode.ReadWrite, bmp.PixelFormat); var image = new Image(w, h); try { byte* sourcePtrBase = (byte*)data.Scan0; long sourceRowByteCount = data.Stride; long destRowByteCount = w * sizeof(Bgr24); Configuration configuration = image.GetConfiguration(); Buffer2D imageBuffer = image.Frames.RootFrame.PixelBuffer; using (IMemoryOwner workBuffer = Configuration.Default.MemoryAllocator.Allocate(w)) { fixed (Bgr24* destPtr = &workBuffer.GetReference()) { for (int y = 0; y < h; y++) { Span row = imageBuffer.DangerousGetRowSpan(y); byte* sourcePtr = sourcePtrBase + (data.Stride * y); Buffer.MemoryCopy(sourcePtr, destPtr, destRowByteCount, sourceRowByteCount); PixelOperations.Instance.FromBgr24(configuration, workBuffer.GetSpan().Slice(0, w), row); } } } } finally { bmp.UnlockBits(data); } return image; } internal static unsafe Bitmap To32bppArgbSystemDrawingBitmap(Image image) where TPixel : unmanaged, IPixel { Configuration configuration = image.GetConfiguration(); int w = image.Width; int h = image.Height; var resultBitmap = new Bitmap(w, h, PixelFormat.Format32bppArgb); var fullRect = new System.Drawing.Rectangle(0, 0, w, h); BitmapData data = resultBitmap.LockBits(fullRect, ImageLockMode.ReadWrite, resultBitmap.PixelFormat); try { byte* destPtrBase = (byte*)data.Scan0; long destRowByteCount = data.Stride; long sourceRowByteCount = w * sizeof(Bgra32); image.ProcessPixelRows(accessor => { using IMemoryOwner workBuffer = image.GetConfiguration().MemoryAllocator.Allocate(w); fixed (Bgra32* sourcePtr = &workBuffer.GetReference()) { for (int y = 0; y < h; y++) { Span row = accessor.GetRowSpan(y); PixelOperations.Instance.ToBgra32(configuration, row, workBuffer.GetSpan()); byte* destPtr = destPtrBase + (data.Stride * y); Buffer.MemoryCopy(sourcePtr, destPtr, destRowByteCount, sourceRowByteCount); } } }); } finally { resultBitmap.UnlockBits(data); } return resultBitmap; } }