如何使用LockBits和BitmapData垂直合并两张位图(C#)
32bppArgb格式位图垂直合并的不安全模式实现
需求说明
需要实现一个C#函数,将两张32bppArgb格式的位图垂直合并(上下排列),返回合并后的新位图。此前使用GDI+的方法存在像素失真问题,因此采用不安全模式直接操作像素数据来解决。
完善后的完整代码
using System; using System.Drawing; using System.Drawing.Imaging; public static unsafe Bitmap merge_Two_Bitmaps32bppArgb_Vertically(Bitmap imageSrc1, Bitmap imageSrc2) { if (imageSrc1 == null || imageSrc2 == null) throw new ArgumentNullException("输入位图不能为空"); // 校验输入位图格式,仅支持32bppArgb if (imageSrc1.PixelFormat != PixelFormat.Format32bppArgb || imageSrc2.PixelFormat != PixelFormat.Format32bppArgb) { throw new ArgumentException("仅支持32bppArgb格式的位图"); } int maxWidth = Math.Max(imageSrc1.Width, imageSrc2.Width); int totalHeight = imageSrc1.Height + imageSrc2.Height; Bitmap mergedBitmap = new Bitmap(maxWidth, totalHeight, PixelFormat.Format32bppArgb); BitmapData src1Data = null; BitmapData src2Data = null; BitmapData destData = null; try { // 锁定源位图1,只读模式 src1Data = imageSrc1.LockBits( new Rectangle(0, 0, imageSrc1.Width, imageSrc1.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb); // 锁定源位图2,只读模式 src2Data = imageSrc2.LockBits( new Rectangle(0, 0, imageSrc2.Width, imageSrc2.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb); // 锁定目标位图,写入模式(原代码用ReadOnly无法写入数据,是核心错误) destData = mergedBitmap.LockBits( new Rectangle(0, 0, maxWidth, totalHeight), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb); // 计算每行的字节步长(32位像素占4字节) int src1Stride = src1Data.Stride; int src2Stride = src2Data.Stride; int destStride = destData.Stride; // 获取像素数据起始指针 byte* src1Ptr = (byte*)src1Data.Scan0.ToPointer(); byte* src2Ptr = (byte*)src2Data.Scan0.ToPointer(); byte* destPtr = (byte*)destData.Scan0.ToPointer(); // 复制第一张图到目标位图上半部分 for (int y = 0; y < imageSrc1.Height; y++) { Buffer.MemoryCopy( src1Ptr + y * src1Stride, destPtr + y * destStride, destStride, imageSrc1.Width * 4); } // 复制第二张图到目标位图下半部分 int destYOffset = imageSrc1.Height; for (int y = 0; y < imageSrc2.Height; y++) { Buffer.MemoryCopy( src2Ptr + y * src2Stride, destPtr + (destYOffset + y) * destStride, destStride, imageSrc2.Width * 4); } } finally { // 必须解锁所有位图,防止资源泄漏 if (src1Data != null) imageSrc1.UnlockBits(src1Data); if (src2Data != null) imageSrc2.UnlockBits(src2Data); if (destData != null) mergedBitmap.UnlockBits(destData); } return mergedBitmap; }
关键改进点说明
- 修正锁定模式:将目标位图的
ImageLockMode改为WriteOnly,原代码使用ReadOnly无法写入数据,是导致功能失效的核心问题。 - 格式校验:增加输入位图格式检查,确保仅处理32bppArgb格式,避免格式不兼容引发的像素失真。
- 资源安全:使用
try-finally块确保所有BitmapData被正确解锁,防止内存泄漏。 - 高效像素复制:采用
Buffer.MemoryCopy进行字节级批量复制,比逐像素操作更高效,同时避免手动操作像素可能出现的失真。 - 边界处理:自动处理两张图宽度不一致的情况,宽度不足的区域保持默认透明(32bppArgb位图初始化时Alpha通道为0)。
内容的提问来源于stack exchange,提问作者pl.lepko
相关产品推荐
相关产品推荐

