// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using System; using System.Buffers; using System.Drawing; using System.Drawing.Imaging; using SixLabors.ImageSharp.Advanced; using SixLabors.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 : struct, IPixel { int w = bmp.Width; int h = bmp.Height; var fullRect = new 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); byte* sourcePtrBase = (byte*)data.Scan0; long sourceRowByteCount = data.Stride; long destRowByteCount = w * sizeof(Bgra32); var image = new Image(w, h); using (IMemoryOwner workBuffer = Configuration.Default.MemoryAllocator.Allocate(w)) { fixed (Bgra32* destPtr = &workBuffer.GetReference()) { for (int y = 0; y < h; y++) { Span row = image.Frames.RootFrame.GetPixelRowSpan(y); byte* sourcePtr = sourcePtrBase + (data.Stride * y); Buffer.MemoryCopy(sourcePtr, destPtr, destRowByteCount, sourceRowByteCount); PixelOperations.Instance.PackFromBgra32(workBuffer.GetSpan(), row, row.Length); } } } 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 : struct, IPixel { int w = bmp.Width; int h = bmp.Height; var fullRect = new 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); byte* sourcePtrBase = (byte*)data.Scan0; long sourceRowByteCount = data.Stride; long destRowByteCount = w * sizeof(Bgr24); var image = new Image(w, h); using (IMemoryOwner workBuffer = Configuration.Default.MemoryAllocator.Allocate(w)) { fixed (Bgr24* destPtr = &workBuffer.GetReference()) { for (int y = 0; y < h; y++) { Span row = image.Frames.RootFrame.GetPixelRowSpan(y); byte* sourcePtr = sourcePtrBase + (data.Stride * y); Buffer.MemoryCopy(sourcePtr, destPtr, destRowByteCount, sourceRowByteCount); PixelOperations.Instance.PackFromBgr24(workBuffer.GetSpan(), row, row.Length); } } } return image; } internal static unsafe Bitmap To32bppArgbSystemDrawingBitmap(Image image) where TPixel : struct, IPixel { int w = image.Width; int h = image.Height; var resultBitmap = new Bitmap(w, h, PixelFormat.Format32bppArgb); var fullRect = new Rectangle(0, 0, w, h); BitmapData data = resultBitmap.LockBits(fullRect, ImageLockMode.ReadWrite, resultBitmap.PixelFormat); byte* destPtrBase = (byte*)data.Scan0; long destRowByteCount = data.Stride; long sourceRowByteCount = w * sizeof(Bgra32); using (IMemoryOwner workBuffer = image.GetConfiguration().MemoryAllocator.Allocate(w)) { fixed (Bgra32* sourcePtr = &workBuffer.GetReference()) { for (int y = 0; y < h; y++) { Span row = image.Frames.RootFrame.GetPixelRowSpan(y); PixelOperations.Instance.ToBgra32(row, workBuffer.GetSpan(), row.Length); byte* destPtr = destPtrBase + (data.Stride * y); Buffer.MemoryCopy(sourcePtr, destPtr, destRowByteCount, sourceRowByteCount); } } } resultBitmap.UnlockBits(data); return resultBitmap; } } }