0

这是从多个线程渲染到单个位图对象的后续内容

我试图实现的是使用位图 LockBits 函数或任何其他但不是 graphics.DrawImage 的位图,将其绘制到更大图像上任何点的 50x50 像素位图并绘制到更大的位图(100x100 像素)上。我不想使用 DrawImage 的原因在另一个线程中说明。

我已经设法通过使用 Marshal.Copy 从源 BitmapData 到 dest BitmapData 得到一些东西,但它创建了一个平铺的水平拉伸图像。

4

3 回答 3

4

您可以在不依赖任何系统调用的情况下操作内存中的图像。如果您深入研究 .BMP 文件的底层格式,您可以构建自己的设备独立位图类,该类真正“理解”.BMP 的低级格式。

例如,每像素 8 位的图像本质上是一个二维字节数组(每个字节为 1 个像素)加上一个简单的颜色表。粗略地说(这是非常非常粗略的):

byte[,] bColors = new byte[3,256]; // 256 RGB colors
byte[,] bImage = new byte[25,50]; // 25 x 50 pixels 

诀窍是(一如既往)获取原始像素数据,进行处理,然后根据您的更改更新原始像素数据。

过去,我通过将 GDI HBITMAP 转换为 24bpp DIB 来解决此问题,对原始像素进行时髦的图像处理(每像素 3 个字节使这更容易),然后将 DIB 转换回 HBITMAP。这一切都只使用了经典的 GDI(甚至是 GDI+ 之前的版本,更不用说 C#了)。

使用这种方法,您可以设计一个控制结构,以允许多个作者访问您更大图像的不同部分。

但是...低级 BitBlt GDI 调用可能比您可以做的任何事情都更有效率。如果我是你,我会确定连续执行 50 或 100 个 bitblt 会太慢(你可能需要在 c++ 中执行此操作)。

处理 DIB 最烦人的挑战是:

  1. 将 DIB 转换为准备好显示的实际“图像”
  2. 将实际的“图像”转换为 DIB
  3. 将 DIB 保存为 .BMP 以外的其他内容

当我开始学习图像实际上是“恐怖”时的核心参考:

你如何去/从 .NET Image 的......嗯......这是一个很好的问题 :)

于 2009-03-18T01:10:51.017 回答
1

如果您使用的是 32bpp [P]ARGB 像素格式,则使用 LockBits/BitmapData 应该可以正常工作。诀窍是您必须一次复制一行数据,以便它在正确的位置对齐。您应该可以使用以下方法执行此操作:

Rectangle srcArea = new Rectangle(0, 0, srcBitmap.Width, srcBitmap.Height);
BitmapData srcData = srcBitmap.LockBits(srcArea, ImageLockMode.ReadOnly, destBitmap.PixelFormat);
Rectangle destArea = new Rectangle(25, 25, srcBitmap.Width, srcBitmap.Height);
BitmapData destData = destBitmap.LockBits(destArea, ImageLockMode.WriteOnly, destBitmap.PixelFormat);

IntPtr srcPtr = srcData.Scan0;
IntPtr destPtr = destData.Scan0;
byte[] buffer = new byte[srcData.Stride];
for (int i = 0; i < srcData.Height; ++i)
{
    Marshal.Copy(srcPtr, buffer, 0, buffer.Length);
    Marshal.Copy(buffer, 0, destPtr, buffer.Length);

    srcPtr += srcData.Stride;
    destPtr += destData.Stride;
}

srcBitmap.UnlockBits(srcData);
destBitmap.UnlockBits(destData);

作为警告,此代码不会按原样工作,因为我不确定增加 IntPtr 的正确咒语是什么。我以前做过同样类型的事情,但在 C++ 中。另外,我不知道是否有办法直接复制数据而不是使用中间缓冲区。

另一个警告:LockBits 调用 srcBitmap 和缓冲区大小假定 srcBitmap 将完全包含在 destBitmap 中。如果不是这种情况(位图的某些部分将被裁剪掉),则需要调整锁定区域和缓冲区的大小。

如果不使用 32bpp 像素格式(即 24bpp),会比较困难。源 BitmapData 的步幅可能包括一些不应复制的填充。您可以通过计算源行中的实际像素数据量来解决此问题,然后复制该数量。索引像素格式将更加有效。

于 2009-05-19T23:35:22.587 回答
0

我建议看一下内部位图内存结构。

我认为最好的方法是不要尝试直接设置 BitmapData。相反,我会制作一个大小合适的共享字节数组,并直接从较小的图像中设置字节数组。

当您合成较大的图像时,您可以获取最终的字节数组并直接从字节数据中制作位图。

这样做的好处是允许您控制内存管理、线程化操作等,就像您在原始帖子中似乎想要做的那样。数据访问也应该非常快。

于 2009-03-18T01:09:39.960 回答