由于假设对于复制的特定图像不正确,您的图像复制代码有几个错误。首先假设我们,当您为复制操作创建新目标图像时,它将具有与源图像完全相同的像素表示,这有时可能是正确的,但在许多情况下不会:
Bitmap resImg = new Bitmap(foreImg.Width, foreImg.Height);
应该改为:
Bitmap resImg = new Bitmap(foreImg.Width, foreImg.Height, foreImg.PixelFormat);
根据图像可能会或可能不会出错的下一个假设是一个隐含的假设,即源图像PixelFormat
的大小正好是 3 个字节并且对应于PixelFormat.Format24bppRgb
格式(或 3 个字节的倍数,因为我不知道红色、绿色的大小是多少或像素结构中的蓝色通道,它可能是PixelFormat.Format48bppRgb
格式),因此基于此假设将字节从源图像复制到目标图像。
要执行精确复制,必须将完全相同数量的字节从源图像复制到目标图像,并且不需要使用底层Pixel
结构,而是可以基于整数复制。最后但并非最不重要的一点是,如果目标是复制图像而不是逐像素分析其内容,最快的方法是使用专门的内存复制功能:
System.Buffer.MemoryCopy((void*)oneBits.Scan0, (void*)thrBits.Scan0, byteLength, byteLength);
下面有一个代码清单,其中包含使用ulong
as复制图像的代码carrier
。我添加了以字节为单位返回Pixel
大小的函数,用于计算以字节为单位的图像大小并执行精确复制。然而,它可以用来选择匹配Pixel
结构,然后可以用来分析图像数据。例如,如果图像具有PixelFormat.Format24bppRgb
格式,则可以使用Pixel
3 字节大小和 RGB 颜色的结构。对于其他格式,有必要定义Pixel
直接复制图像Pixel
格式的其他结构。
using System;
using System.Drawing;
using System.Drawing.Imaging;
namespace DrawingImagingOperations
{
class Program
{
static void Main(string[] args)
{
Bitmap foreImg = new Bitmap(@"..\..\YaHI9.jpg");
//output image
Bitmap resImg = new Bitmap(foreImg.Width, foreImg.Height, foreImg.PixelFormat);
unsafe
{
BitmapData oneBits = foreImg.LockBits(new Rectangle(0, 0, foreImg.Width, foreImg.Height), ImageLockMode.ReadOnly, foreImg.PixelFormat);
BitmapData thrBits = resImg.LockBits(new Rectangle(0, 0, resImg.Width, resImg.Height), ImageLockMode.WriteOnly, resImg.PixelFormat);
int pixelSize = GetPixelSize(foreImg.PixelFormat);
var byteLength = foreImg.Width * foreImg.Height * pixelSize;
var length = byteLength / sizeof(UInt64);
var reminder = byteLength % sizeof(UInt64);
System.Threading.Tasks.Parallel.For(0, length, j =>
{
ulong* pxOne = (ulong*)((byte*)oneBits.Scan0 + j * sizeof(UInt64));
ulong* pxRes = (ulong*)((byte*)thrBits.Scan0 + j * sizeof(UInt64));
*pxRes = *pxOne;
});
if (reminder > 0)
{
byte* pSrc = (byte*)oneBits.Scan0 + (pixelSize * length);
byte* pDst = (byte*)thrBits.Scan0 + (pixelSize * length);
for (int j = length; j < byteLength; j++)
*pDst++ = *pSrc++;
}
foreImg.UnlockBits(oneBits);
resImg.UnlockBits(thrBits);
}
resImg.Save(@"..\..\imgCopy.jpg");
}
internal static int GetPixelSize(PixelFormat data)
{
switch (data)
{
case PixelFormat.Format8bppIndexed:
return 1;
case PixelFormat.Format16bppGrayScale:
case PixelFormat.Format16bppRgb555:
case PixelFormat.Format16bppRgb565:
case PixelFormat.Format16bppArgb1555:
return 2;
case PixelFormat.Format24bppRgb:
return 3;
case PixelFormat.Canonical:
case PixelFormat.Format32bppArgb:
case PixelFormat.Format32bppPArgb:
case PixelFormat.Format32bppRgb:
return 4;
case PixelFormat.Format48bppRgb:
return 6;
case PixelFormat.Format64bppArgb:
case PixelFormat.Format64bppPArgb:
return 8;
}
throw new FormatException("Unsupported image format: " + data);
}
}
}