Since you did not specify what platform you´re targeting, I assume (for simplicity) the platform is Windows (because GDI+ and the System.Drawing API is only fully available on that platform). Further, I assume you target one of the more recent versions of .NET, for instance, .NET 6.0 LTS.
I provide you with some sample code that avoids usage of the functionality that deals with the Stride pointer and raw image data. I use the System.Drawing.Common package in my example. If you´re working on an older version of the .NET Framework, adding a reference to System.Drawing should also work.
The following method accepts an array of Image objects. It takes the width and the pixel format of the first image and calculates the height of the resulting image by just summing up the heights of all images. It renders all images unscaled, so you need to tweak it to your needs; maybe you want to specify the width of the resulting image as a parameter and scale all images accordingly.
private static Image MergeBitmaps(params Image[] bitmaps)
{
Image first = bitmaps.FirstOrDefault() ?? throw new InvalidOperationException();
int width = first.Width;
int resultImageHeight = bitmaps.Sum(bitmap => bitmap.Height);
var offset = 0;
var resultImage = new Bitmap(width, resultImageHeight, first.PixelFormat);
using Graphics g = Graphics.FromImage(resultImage);
foreach (Image bitmap in bitmaps)
{
g.DrawImageUnscaled(bitmap, 0, offset, bitmap.Width, bitmap.Height);
offset += bitmap.Height;
}
return resultImage;
}
Also, I would use the Image type rather than Bitmap. You could use the provided example method as follows:
using Image bitmap1 = Image.FromStream(...);
using Image bitmap2 = Image.FromStream(...);
using Image mergedImage = MergeBitmaps(bitmap1, bitmap2);
mergedImage.Save(Path.Combine(path, "merged.bmp"));
As mentioned in my comment, you should only work the raw bitmap data if you developed an understanding of how the pixel information in the buffer is laid out. Your implementation may require calculations and pixel conversions to support images of different pixel formats. If performance is not an issue, having code, as provided in my example, that renders the target image using a Graphics object may be less complex and easier to work with.
Update
If you want to combine the images by copying the raw bitmap buffers into the resulting image, ensure all input images have the same width and pixel format, and the pixel format also matches the format of the resulting image (which is 32bppArgb in that case). Then you could try something like this (this needs proper testing and additional checks):
private static Image MergeBitmaps(params Bitmap[] bitmaps)
{
int width = bitmaps.Max(bitmap => bitmap.Width);
int resultImageHeight = bitmaps.Sum(bitmap => bitmap.Height);
var offset = 0;
var pixelFormat = PixelFormat.Format32bppArgb;
var resultImage = new Bitmap(width, resultImageHeight, pixelFormat);
foreach (Bitmap bitmap in bitmaps)
{
int bitmapHeight = bitmap.Height;
var rectangle = new Rectangle(0, offset, width, bitmapHeight);
CopyBitmap(resultImage, rectangle, bitmap);
offset += bitmapHeight;
}
return resultImage;
}
private static void CopyBitmap(
Bitmap destBitmap,
Rectangle destinationRectange,
Bitmap sourceBitmap)
{
BitmapData resultBitmapData = destBitmap.LockBits(destinationRectange,
ImageLockMode.WriteOnly,
destBitmap.PixelFormat);
try
{
var bytes = new byte[resultBitmapData.Stride * resultBitmapData.Height];
var rect = new Rectangle(0, 0, sourceBitmap.Width, sourceBitmap.Height);
BitmapData bitmapData = sourceBitmap.LockBits(rect,
ImageLockMode.ReadOnly,
sourceBitmap.PixelFormat);
try
{
var array = new byte[bitmapData.Stride * bitmapData.Height];
Marshal.Copy(bitmapData.Scan0, array, 0, array.Length);
Array.Copy(array, bytes, array.Length);
}
finally
{
sourceBitmap.UnlockBits(bitmapData);
}
Marshal.Copy(bytes, 0, resultBitmapData.Scan0, bytes.Length);
}
finally
{
destBitmap.UnlockBits(resultBitmapData);
}
}
merge verticallymean in the first place?Mergesuggests you want to combine two images butverticallysuggests you want to append one below the other. Which is easy - create a new bitmap with twice the height and draw the existing ones one after the other.MergeBitmapsexample method to my answer that demos how you can combine the images by copying raw bitmap buffers. As mentioned, I would not recommend doing this, but you asked for it (-: