This simple class allows us to hide a byte[] inside the Scan0 of a Bitmap's BitmapData and later retrieve the byte[] hidden within. Is there any cases where padding would be an issue?
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;
public record class IMG(byte[] Data)
{
const ImageLockMode Read = ImageLockMode.ReadOnly;
const ImageLockMode Write = ImageLockMode.WriteOnly;
const PixelFormat Format = PixelFormat.Format32bppArgb;
// Start Size Approximation
private readonly int Size = Data.Length >> 2;
public int Width => GetSize(Math.Sqrt(Size));
public int Height => GetSize((double)Size / Width);
static int GetSize(double x) => (int)Math.Ceiling(x);
// End Size Approximation
public Bitmap Build()
{
var rect = new Rectangle(0, 0, Width, Height);
var result = new Bitmap(Width, Height, Format);
var bitData = result.LockBits(rect, Write, Format);
Marshal.Copy(Data, 0, bitData.Scan0, Data.Length);
result.UnlockBits(bitData);
return result;
}
[DebuggerStepThrough, DebuggerHidden]
public static IMG? Load(Bitmap bitmap)
{
ArgumentNullException.ThrowIfNull(bitmap);
if (bitmap.PixelFormat != Format)
throw new NotSupportedException(nameof(bitmap));
var rect = new Rectangle(0, 0, bitmap.Width, bitmap.Height);
var bitData = bitmap.LockBits(rect, Read, Format);
var size = bitData.Height * bitData.Stride;
var result = new byte[size];
Marshal.Copy(bitData.Scan0, result, 0, size);
bitmap.UnlockBits(bitData);
return new(result);
}
}
GetValuedoing something completely different. The nameGetValuedoes not give any clue on what these functions are doing. You must read their implementations in order to understand and also be sure to understand which overload will be called. I would keep only the first one and name itIntCeilingand then get the width withpublic int Width => IntCeiling(Math.Sqrt(Size));. This adds a lot of clarity. \$\endgroup\$try..finallybetweenLockBitsandUnlockBitsto ensure that they are unlocked no matter if an exception occurs in the interceding code. \$\endgroup\$Rectangle rect = new(0, 0, Width, Height); Bitmap result = new(rect.Width, rect.Height, Format);(note using the width and height of the rectangle instead) \$\endgroup\$