【问题标题】:C# draw bitmap from integerC#从整数绘制位图
【发布时间】:2016-01-25 18:02:01
【问题描述】:

我必须从整数值中绘制图像。它们存储在List<int>[]。 该列表有 5081 个数组,每个数组有 2048 个值。每个值都在 0-1000 之间,一个 int 是一个像素的颜色,所以它是灰度的。

我知道如何用 setpixel 来做,但这太慢了。

for (int y = 0; y < channelId.Length; y++) {
            for (int x = 0; x < channelId[y].Count; x++) {
                int myColor = (channelId[y].ElementAt(x) * 255) / 1000;
                if (myColor > 255) {
                    myColor = 255;
                } else if (myColor < 0) {
                    myColor = 0;
                }
                bmp.SetPixel(x, y, Color.FromArgb(myColor, myColor, myColor));
            }
        }

我知道这里有类似的问题如何更快地绘制位图,但他们已经有了位图。我必须根据我的价值观绘制图像。

【问题讨论】:

  • @stuartd 虽然链接的问题大致相同,但它专门标记为wpf(并且接受的答案肯定是wpf,因为它使用ImageSourceWriteableBitmap,而不是Bitmap正如对这个问题的预期)

标签: c# bitmap


【解决方案1】:

如果你不想这样做不安全,你可以这样做(假设32bppArgb像素格式):

var rect = new Rectangle(0, 0, bmp.Width, bmp.Height);
var bmpData = bmp.LockBits(rect, ImageLockMode.WriteOnly, bmp.PixelFormat);
IntPtr ptr = bmpData.Scan0;
for (var y = 0; y < channelId.Length; y++)
{
    var scanLineSize = channelId[y].Count*4;
    var rgb = new byte[scanLineSize];
    int idx = 0;
    // Convert the whole scanline
    foreach (var id in channelId[y])
    {
        rgb[idx] = rgb[idx+1] = rgb[idx+2] = (byte)(id*255/1000);
        rgb[idx+3] = 255;
        idx += 4;
    }
    // And copy it in one pass
    System.Runtime.InteropServices.Marshal.Copy(rgb, 0, ptr, scanLineSize);
    ptr += bmpData.Stride;
}
bmp.UnlockBits(bmpData);

如果它对您来说不够快,您可以在内存中完成位图的整个转换并一次性复制整个数组。不过,这不会非常节省内存,而且对于您要移动的数据量来说,这应该“足够快”。

更新

只是为了好玩,一次通过:

var rect = new Rectangle(0, 0, bmp.Width, bmp.Height);
var bmpData = bmp.LockBits(rect, ImageLockMode.WriteOnly, bmp.PixelFormat);
IntPtr ptr = bmpData.Scan0;
int idx = 0;
var rgb = new byte[channelId[0].Count * 4 * channelId.Length];
foreach (var id in channelId.SelectMany(t => t))
{
    rgb[idx] = rgb[idx+1] = rgb[idx+2] = (byte)(id*255/1000);
    rgb[idx+3] = 255;
    idx += 4;
}
System.Runtime.InteropServices.Marshal.Copy(rgb, 0, ptr, rgb.Length);
bmp.UnlockBits(bmpData);

除了内存效率之外,您还需要确保数组中的所有List&lt;int&gt; 包含相同数量的元素,并且位图的Stridewidth*4 相同。应该是 2048 个元素,但你永远不知道。

【讨论】:

  • 我添加了一次性转换,只是为了好玩,这确实可以进一步优化(不使用 alpha 等),但我将把它留作练习! :-)
【解决方案2】:
BitmapData bitmapData = bmp.LockBits(
    new Rectangle(0, 0, channelId[0].Count, channelId.Length),
    ImageLockMode.ReadWrite,
    PixelFormat.Format32bppArgb
);
unsafe{
 ColorARGB* startingPosition = (ColorARGB*) bitmapData.Scan0;
 for (int y = 0; y < channelId.Length; y++) {
        for (int x = 0; x < channelId[y].Count; x++) {
            int myColor = (channelId[y].ElementAt(x) * 255) / 1000;
            if (myColor > 255) {
                myColor = 255;
            } else if (myColor < 0) {
                myColor = 0;
            }

            ColorARGB* position = startingPosition + j + i * channelId[0].Count;
            position->A = 255;
            position->R = myColor;
            position->G = myColor;
            position->B = myColor;
        }
    }
    bmp.UnlockBits(bitmapData);
   }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-06-22
    • 2013-02-03
    • 1970-01-01
    • 2011-01-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多