在窗体上将字节数组显示为图像
Show an array of bytes as an image on a form
我写了一些代码来将字节数组显示为图像。有一个字节数组,其中每个元素代表一个 8 位灰度图像的值。零等于最黑像素,255 代表最白像素。我的目标是将这个 w*w 像素的灰度图像转换为 pictureBox1.Image
接受的某种东西。
这是我的代码:
namespace ShowRawImage
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
int i = 0, j = 0, w = 256;
byte[] rawIm = new byte[256 * 256];
for(i = 0; i < w; ++i)
{
for (j = 0; j < w; ++j)
{
rawIm[i * w + j] = (byte)j; // BitConverter.GetBytes(j);
}
}
MemoryStream mStream = new MemoryStream();
mStream.Write(rawIm, 0, Convert.ToInt32(rawIm.Length));
Bitmap bm = new Bitmap(mStream, false);// the error occurs here
mStream.Dispose();
pictureBox1.Image = bm;
}
}
}
但是我得到这个错误:
参数无效。
The error snapshot
我的错误在哪里?
编辑:
在下一步中,我将显示 16 位灰度图像。
如评论中所述 - 位图不仅仅是一个数组。因此,为了达到您的目标,您可以创建所需大小的位图并使用 Bitmap.SetPixel
:
设置像素
Bitmap bm = new Bitmap(w, w);
for(var i = 0; i < w; ++i)
{
for (var j = 0; j < w; ++j)
{
bm.SetPixel(i,j, Color.FromArgb(j, j, j));
}
}
Bitmap(Stream, bool)
构造函数需要一个具有实际图像格式(例如 PNG、GIF 等)的流以及 header、调色板和可能的压缩图像数据。
要从原始数据创建 Bitmap
,您需要使用 Bitmap(int width, int height, int stride, PixelFormat format, IntPtr scan0)
构造函数,但这也很不方便,因为您需要一个可以作为 [=17 传递的固定原始数据=].
如果您只创建带有灰度调色板的 8bpp 位图并手动设置像素,则最好:
var bmp = new Bitmap(256, 256, PixelFormat.Format8bppIndexed);
// making it grayscale
var palette = bmp.Palette;
for (int i = 0; i < 255; i++)
palette.Entries[i] = Color.FromArgb(i, i, i);
bmp.Palette = palette;
现在您可以以字节形式访问其原始内容,其中 0 为黑色,255 为白色:
var bitmapData = bmp.LockBits(new Rectangle(Point.Empty, bmp.Size), ImageLockMode.WriteOnly, PixelFormat.Format8bppIndexed);
for (int y = 0; y < bitmapData.Height; y++)
{
for (int x = 0; x < bitmapData.Width; x++)
{
unsafe
{
((byte*) bitmapData.Scan0)[y * bitmapData.Stride + x] = (byte)x;
}
}
}
bmp.UnlockBits(bitmapData);
但是如果你不想使用不安全的代码,或者你想按颜色设置像素,你可以使用this library (disclaimer: written by me) that supports efficient manipulation而不考虑实际的PixelFormat
。使用该库可以像这样重写最后一个块:
using (IWritableBitmapData bitmapData = bmp.GetWritableBitmapData())
{
IWritableBitmapDataRow row = bitmapData.FirstRow;
do
{
for (int x = 0; x < bitmapData.Width; x++)
row[x] = Color32.FromGray((byte)x); // this works for any pixel format
// row.SetColorIndex(x, x); // for the grayscale 8bpp bitmap created above
} while (row.MoveNextRow());
}
或者像这样,使用 Parallel.For
(这只是因为在您的示例中所有行都相同,所以图像是水平渐变):
using (IWritableBitmapData bitmapData = bmp.GetWritableBitmapData())
{
Parallel.For(0, bitmapData.Height, y =>
{
var row = bitmapData[y];
for (int x = 0; x < bitmapData.Width; x++)
row[x] = Color32.FromGray((byte)x); // this works for any pixel format
// row.SetColorIndex(x, x); // for the grayscale 8bpp bitmap created above
});
}
我写了一些代码来将字节数组显示为图像。有一个字节数组,其中每个元素代表一个 8 位灰度图像的值。零等于最黑像素,255 代表最白像素。我的目标是将这个 w*w 像素的灰度图像转换为 pictureBox1.Image
接受的某种东西。
这是我的代码:
namespace ShowRawImage
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
int i = 0, j = 0, w = 256;
byte[] rawIm = new byte[256 * 256];
for(i = 0; i < w; ++i)
{
for (j = 0; j < w; ++j)
{
rawIm[i * w + j] = (byte)j; // BitConverter.GetBytes(j);
}
}
MemoryStream mStream = new MemoryStream();
mStream.Write(rawIm, 0, Convert.ToInt32(rawIm.Length));
Bitmap bm = new Bitmap(mStream, false);// the error occurs here
mStream.Dispose();
pictureBox1.Image = bm;
}
}
}
但是我得到这个错误:
参数无效。
The error snapshot
我的错误在哪里?
编辑: 在下一步中,我将显示 16 位灰度图像。
如评论中所述 - 位图不仅仅是一个数组。因此,为了达到您的目标,您可以创建所需大小的位图并使用 Bitmap.SetPixel
:
Bitmap bm = new Bitmap(w, w);
for(var i = 0; i < w; ++i)
{
for (var j = 0; j < w; ++j)
{
bm.SetPixel(i,j, Color.FromArgb(j, j, j));
}
}
Bitmap(Stream, bool)
构造函数需要一个具有实际图像格式(例如 PNG、GIF 等)的流以及 header、调色板和可能的压缩图像数据。
要从原始数据创建 Bitmap
,您需要使用 Bitmap(int width, int height, int stride, PixelFormat format, IntPtr scan0)
构造函数,但这也很不方便,因为您需要一个可以作为 [=17 传递的固定原始数据=].
如果您只创建带有灰度调色板的 8bpp 位图并手动设置像素,则最好:
var bmp = new Bitmap(256, 256, PixelFormat.Format8bppIndexed);
// making it grayscale
var palette = bmp.Palette;
for (int i = 0; i < 255; i++)
palette.Entries[i] = Color.FromArgb(i, i, i);
bmp.Palette = palette;
现在您可以以字节形式访问其原始内容,其中 0 为黑色,255 为白色:
var bitmapData = bmp.LockBits(new Rectangle(Point.Empty, bmp.Size), ImageLockMode.WriteOnly, PixelFormat.Format8bppIndexed);
for (int y = 0; y < bitmapData.Height; y++)
{
for (int x = 0; x < bitmapData.Width; x++)
{
unsafe
{
((byte*) bitmapData.Scan0)[y * bitmapData.Stride + x] = (byte)x;
}
}
}
bmp.UnlockBits(bitmapData);
但是如果你不想使用不安全的代码,或者你想按颜色设置像素,你可以使用this library (disclaimer: written by me) that supports efficient manipulation而不考虑实际的PixelFormat
。使用该库可以像这样重写最后一个块:
using (IWritableBitmapData bitmapData = bmp.GetWritableBitmapData())
{
IWritableBitmapDataRow row = bitmapData.FirstRow;
do
{
for (int x = 0; x < bitmapData.Width; x++)
row[x] = Color32.FromGray((byte)x); // this works for any pixel format
// row.SetColorIndex(x, x); // for the grayscale 8bpp bitmap created above
} while (row.MoveNextRow());
}
或者像这样,使用 Parallel.For
(这只是因为在您的示例中所有行都相同,所以图像是水平渐变):
using (IWritableBitmapData bitmapData = bmp.GetWritableBitmapData())
{
Parallel.For(0, bitmapData.Height, y =>
{
var row = bitmapData[y];
for (int x = 0; x < bitmapData.Width; x++)
row[x] = Color32.FromGray((byte)x); // this works for any pixel format
// row.SetColorIndex(x, x); // for the grayscale 8bpp bitmap created above
});
}