我实际上是wrote a universally usable BuildImagefunction here on SO to build an image out of a byte array,但当然,您不是从字节数组开始,而是从二维Int32 数组开始。绕过它的简单方法就是提前对其进行改造。
您的字节为整数数组是一件相当奇怪的事情。如果这是从灰度图像中读取的,我宁愿假设这是 32 位 ARGB 数据,并且您只使用每个值的最低分量(将是蓝色的),但如果将值向下移动 4 位产生一致的暗值我倾向于相信你的话;否则下一个颜色分量(绿色)的位会渗入,也会产生明亮的颜色。
无论如何,抛开思考和猜测,这是我的实际答案。
你可能认为你的每一个值,当注入一个 8 位图像时,只是亮度,但 这实际上是错误的。 System.Drawing 像素格式中没有具体的类型来表示 8 位灰度,并且 8 位图像是调色,这意味着图像上的每个值都指调色板上的一种颜色.因此,要实际制作一个 8 位灰度图像,其中您的字节值指示像素的亮度,您需要明确定义一个调色板,其中调色板上 0 到 255 的索引包含从 (0,0, 0) 到 (255,255,255)。当然,这很容易生成。
此代码会将您的数组转换为 8 位图像。它使用前面提到的BuildImage 函数。请注意,该函数使用 no 不安全代码。使用Marshal.Copy 意味着永远不会直接处理原始指针,从而使代码完全托管。
public static Bitmap FromTwoDimIntArrayGray(Int32[,] data)
{
// Transform 2-dimensional Int32 array to 1-byte-per-pixel byte array
Int32 width = data.GetLength(0);
Int32 height = data.GetLength(1);
Int32 byteIndex = 0;
Byte[] dataBytes = new Byte[height * width];
for (Int32 y = 0; y < height; y++)
{
for (Int32 x = 0; x < width; x++)
{
// logical AND to be 100% sure the int32 value fits inside
// the byte even if it contains more data (like, full ARGB).
dataBytes[byteIndex] = (Byte)(((UInt32)data[x, y]) & 0xFF);
// More efficient than multiplying
byteIndex++;
}
}
// generate palette
Color[] palette = new Color[256];
for (Int32 b = 0; i < 256; b++)
palette[b] = Color.FromArgb(b, b, b);
// Build image
return BuildImage(dataBytes, width, height, width, PixelFormat.Format8bppIndexed, palette, null);
}
注意,即使整数 是 完整的 ARGB 值,上面的代码仍然可以完全一样地工作;如果你只使用整数内四个字节中的最低值,正如我所说,那将只是完整 ARGB 整数的蓝色分量。如果图像是灰度图像,则所有三个颜色分量都应该相同,因此您仍然会得到相同的结果。
假设您曾经发现自己使用相同类型的字节数组,其中整数实际上确实包含完整的 32bpp ARGB 数据,您必须移出所有四个字节值,并且不会有生成灰色调色板,但除此之外,代码将非常相似。只是,每次 X 迭代处理 4 个字节。
public static Bitmap fromTwoDimIntArrayGray(Int32[,] data)
{
Int32 width = data.GetLength(0);
Int32 height = data.GetLength(1);
Int32 stride = width * 4;
Int32 byteIndex = 0;
Byte[] dataBytes = new Byte[height * stride];
for (Int32 y = 0; y < height; y++)
{
for (Int32 x = 0; x < width; x++)
{
// UInt32 0xAARRGGBB = Byte[] { BB, GG, RR, AA }
UInt32 val = (UInt32)data[x, y];
// This code clears out everything but a specific part of the value
// and then shifts the remaining piece down to the lowest byte
dataBytes[byteIndex + 0] = (Byte)(val & 0x000000FF); // B
dataBytes[byteIndex + 1] = (Byte)((val & 0x0000FF00) >> 08); // G
dataBytes[byteIndex + 2] = (Byte)((val & 0x00FF0000) >> 16); // R
dataBytes[byteIndex + 3] = (Byte)((val & 0xFF000000) >> 24); // A
// More efficient than multiplying
byteIndex+=4;
}
}
return BuildImage(dataBytes, width, height, stride, PixelFormat.Format32bppArgb, null, null);
}
当然,如果你想要这个不透明,你可以像你一样使用三个字节,或者只是在最终调用中将PixelFormat.Format32bppArgb更改为PixelFormat.Format32bppRgb,这会将第四个字节的含义从alpha更改为只是填充。