这似乎是与8位图像有关的事情。8位图像的优点在于,您只需要具有一个一维字节数组和您的值,
就可以将其直接加载到图像中,使用LockBits
和Marshal.Copy
。
嗯,几乎是直接的。在8位图像上,您的像素值实际上并不是您的颜色,它们是对颜色调色板的引用,实际上包含您的颜色。但是,如果您希望图像上的0到255的值表示颜色(0,0,0)到(255,255,255),那么您需要做的就是生成一个具有这256个灰色所需颜色的调色板,这可以在一个简单的for循环中处理。
首先,处理CSV文件。如果这只是简单的“数字,逗号,数字”信息,您可以使用
String.Split
函数,但如果要处理包含引号和/或分割字符的引用块的特殊情况,则需要使用更高级/可靠的CSV解析器
TextFieldParser
。有关更多信息,请单击
此处,但我认为对于这个问题,我们可以采用
String.Split
方法。
我在这里创建了一个名为
startColumn
的变量,以方便您的使用,但在您的情况下,它当然将是“3”。
public static Bitmap GrayImageFromCsv(String[] lines, Int32 startColumn, Int32 maxValue)
{
maxValue = Math.Min(maxValue, 255);
if (lines == null || lines.Length == 0)
return null;
Int32 bottom = lines.Length;
while (bottom > 0 && lines[bottom - 1].Trim().Length == 0)
bottom--;
if (bottom == 0)
return null;
Int32 top = 0;
while (top < bottom && lines[top].Trim().Length == 0)
top++;
Int32 height = bottom - top;
String[][] values = new String[height][];
for (Int32 i = top; i < bottom; i++)
values[i - top] = lines[i].Split(',');
Int32 width = values.Max(line => line.Length) - startColumn;
if (width <= 0)
return null;
Byte[] imageArray = new Byte[width*height];
for (Int32 y = 0; y < height; y++)
{
Int32 offset = y*width;
for (Int32 x = startColumn; x < values[y].Length; x++)
{
Int32 val;
if (Int32.TryParse(values[y][x].Trim(), out val))
imageArray[offset] = (Byte) Math.Max(0, Math.Min(val, maxValue));
offset++;
}
}
Double mulFactor = 255d / maxValue;
Color[] palette = new Color[maxValue + 1];
for (Int32 i = 0; i <= maxValue; i++)
{
Byte g = (Byte)Math.Round(i * mulFactor, MidpointRounding.AwayFromZero);
palette[i] = Color.FromArgb(g, g, g);
}
return BuildImage(imageArray, width, height, width, PixelFormat.Format8bppIndexed, palette, Color.White);
}
Called as:
String[] lines = File.ReadAllLines(path);
using (Bitmap img = GrayImageFromCsv(lines, 3, 15))
{
if (img != null)
img.Save("fromcsv.png", ImageFormat.Png);
}
主处理结束时调用的BuildImage函数执行了上述“将字节数组加载到图像中”的操作。
您可以在这里找到它。请注意,“stride”是图像一行上的字节数量。虽然对于8位图像,这与宽度相同,因为每个字节是一个像素,但对于其他格式,它将有所不同。