// 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.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 : 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;
}
}
}