尝试从 C# WinForms 中的 PictureBox 读取像素颜色
Trying to read pixel color from PictureBox in C# WinForms
我遇到一个奇怪的问题,当我尝试遍历 PictureBox
的像素或保存 bmp 时,它只是全黑。
该工具的目的是 select 一种字体、大小和样式,然后循环遍历该字体的 ASCII 字符并在图片框中显示每个字符,并转换像素将数据转换成 HEX 数组,以便我可以在 LCD 显示器上使用它们。
该工具的主要部分是正确地循环遍历 ASCII 字符并将它们显示在图片框中,但是在将每个字符绘制到图片框之后,我然后尝试遍历 PictureBox
每个像素都返回为 0,0,0 RGB“黑色”,如果我保存绘制到 PictureBox
的 bmp,那也是全黑的,但我又可以看到那个字符的 bmp在 PictureBox
中正确绘制但 PictureBox
数据和 bmp 数据与我在 PictureBox
中看到的不匹配,我真的不知道为什么我无法正确迭代或保存bmp 或 PictureBox
.
我尝试不使用 async
函数,这并不理想,因为我希望 UI 是免费的,我尝试了各种方法来读取像素并保存 bmp 但结果是一样的。我希望问问是否有人知道为什么我会出现这种奇怪的行为以及问题的解决方案。
Ed 的问候
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace generateFonts
{
public partial class Form1 : Form
{
string font = "";
float fontSize = 0;
FontStyle fontStyle = FontStyle.Regular;
public Form1()
{
InitializeComponent();
comboBox1.SelectedIndex = 0;
comboBox2.SelectedIndex = 0;
comboBox3.SelectedIndex = 0;
font = comboBox1.SelectedItem.ToString();
fontSize = Convert.ToInt32(comboBox2.SelectedItem);
fontStyle = FontStyle.Regular;
}
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
font = comboBox1.SelectedItem.ToString();
}
private void comboBox2_SelectedIndexChanged(object sender, EventArgs e)
{
fontSize = Convert.ToInt32(comboBox2.SelectedItem);
}
private void comboBox3_SelectedIndexChanged(object sender, EventArgs e)
{
if (comboBox3.SelectedIndex == 0)
fontStyle = FontStyle.Regular;
else if (comboBox3.SelectedIndex == 1)
fontStyle = FontStyle.Italic;
else if(comboBox3.SelectedIndex == 2)
fontStyle = FontStyle.Bold;
}
private async void button1_Click(object sender, EventArgs e)
{
await Task.Run(() => StartProcess(1));
}
private void StartProcess(int runs)
{
// Font
Font myFont = new Font(font, fontSize, fontStyle);
List<string> bytes = new List<string>();
string[] bits = { "0", "0", "0", "0", "0", "0", "0", "0" };
byte bitPos = 0;
for (byte i = 32; i < 126; i++)
{
//Create a Image-Object on which we can paint
Image bmp = new Bitmap(200, 200);
//Create the Graphics-Object to paint on the Bitmap
Graphics g = Graphics.FromImage(bmp);
string c = Convert.ToChar(i).ToString();
//Get the perfect Image-Size so that Image-Size = String-Size
SizeF size = g.MeasureString(c, myFont);
//Use this to become better Text-Quality on Bitmap.
g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias;
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.PixelOffsetMode = PixelOffsetMode.HighQuality;
//Here we draw the string on the Bitmap
g.DrawString(c, myFont, new SolidBrush(Color.Black), 0, 0);
if (!Directory.Exists("FontBmps"))
Directory.CreateDirectory("FontBmps");
this.Invoke((MethodInvoker)delegate ()
{
pictureBox2.Width = Convert.ToInt32(size.Width);
pictureBox2.Height = Convert.ToInt32(size.Height);
pictureBox2.Image = bmp; // <--- this is working and the picturebox shows the bmp correctly
bmp.Save("FontBmps/" + i + "_" + font + "_" + fontSize + "px_" + fontStyle + ".bmp", ImageFormat.Bmp); // <--- error here: this saves a black square instead of the bmp i see displayed in the picturebox GUI ??
// Even if i save the picturebox itself that too is just a black square instead of the correct image shown in the GUI ??
// now convert the bmp to a HEX array of pixels
for (int h = 0; h < pictureBox2.Height; h++)
{
for (int w = 0; w < pictureBox2.Width; w++)
{
Color colour = (pictureBox2.Image as Bitmap).GetPixel(w, h);
if (colour.R == 0 && colour.G == 0 && colour.B == 0)
{
bits[bitPos] = "1";
}
else
{
bits[bitPos] = "0"; // <-- never hits me, again for some reason the bmp or picturebox is all black pixels data but i see it correctly show in the picturebox GUI ??
}
if (bitPos < 7)
bitPos++;
else
{
//string bitStr = bits.ToString();
//string hex = Convert.ToByte(bitStr, 2).ToString("x2");
//bytes.Add(hex);
bitPos = 0;
for(byte n = 0; n < 8; n++)
{
bits[n] = "0";
}
}
}
}
if (bitPos != 0)
{
// TO DO...
}
});
Thread.Sleep(500); // <--- i have this just to see it displaying the chars but i have removed it with no effect to the issue
}
// now add List to a file in the correct format
foreach (string str in bytes)
{
Console.WriteLine(str);
// TO DO...
}
}
}
}
我认为图像是黑色的,但有些部分是透明的。也就是说,您需要检查 Alpha (Color.A
)。您在图片框中看到的是透明图片框的背景颜色。
您不会在保存的文件中看到透明度,因为 ImageFormat.Bmp
不支持透明度。请尝试 Png
,它支持透明度(并且具有无损压缩)。
或者,您可以使用 Graphics.Clear
将图像设置为您想要的背景颜色(我猜是白色),然后再绘制它。
除此之外,我建议使用 bmp
而不是 (pictureBox2.Image as Bitmap)
,并使用 Bitmap.LockBits
。这将提高性能。
这可能对参考有用:Converting a bitmap to monochrome. See also C# - Faster Alternatives to SetPixel and GetPixel for Bitmaps for Windows Forms App。
我遇到一个奇怪的问题,当我尝试遍历 PictureBox
的像素或保存 bmp 时,它只是全黑。
该工具的目的是 select 一种字体、大小和样式,然后循环遍历该字体的 ASCII 字符并在图片框中显示每个字符,并转换像素将数据转换成 HEX 数组,以便我可以在 LCD 显示器上使用它们。
该工具的主要部分是正确地循环遍历 ASCII 字符并将它们显示在图片框中,但是在将每个字符绘制到图片框之后,我然后尝试遍历 PictureBox
每个像素都返回为 0,0,0 RGB“黑色”,如果我保存绘制到 PictureBox
的 bmp,那也是全黑的,但我又可以看到那个字符的 bmp在 PictureBox
中正确绘制但 PictureBox
数据和 bmp 数据与我在 PictureBox
中看到的不匹配,我真的不知道为什么我无法正确迭代或保存bmp 或 PictureBox
.
我尝试不使用 async
函数,这并不理想,因为我希望 UI 是免费的,我尝试了各种方法来读取像素并保存 bmp 但结果是一样的。我希望问问是否有人知道为什么我会出现这种奇怪的行为以及问题的解决方案。
Ed 的问候
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace generateFonts
{
public partial class Form1 : Form
{
string font = "";
float fontSize = 0;
FontStyle fontStyle = FontStyle.Regular;
public Form1()
{
InitializeComponent();
comboBox1.SelectedIndex = 0;
comboBox2.SelectedIndex = 0;
comboBox3.SelectedIndex = 0;
font = comboBox1.SelectedItem.ToString();
fontSize = Convert.ToInt32(comboBox2.SelectedItem);
fontStyle = FontStyle.Regular;
}
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
font = comboBox1.SelectedItem.ToString();
}
private void comboBox2_SelectedIndexChanged(object sender, EventArgs e)
{
fontSize = Convert.ToInt32(comboBox2.SelectedItem);
}
private void comboBox3_SelectedIndexChanged(object sender, EventArgs e)
{
if (comboBox3.SelectedIndex == 0)
fontStyle = FontStyle.Regular;
else if (comboBox3.SelectedIndex == 1)
fontStyle = FontStyle.Italic;
else if(comboBox3.SelectedIndex == 2)
fontStyle = FontStyle.Bold;
}
private async void button1_Click(object sender, EventArgs e)
{
await Task.Run(() => StartProcess(1));
}
private void StartProcess(int runs)
{
// Font
Font myFont = new Font(font, fontSize, fontStyle);
List<string> bytes = new List<string>();
string[] bits = { "0", "0", "0", "0", "0", "0", "0", "0" };
byte bitPos = 0;
for (byte i = 32; i < 126; i++)
{
//Create a Image-Object on which we can paint
Image bmp = new Bitmap(200, 200);
//Create the Graphics-Object to paint on the Bitmap
Graphics g = Graphics.FromImage(bmp);
string c = Convert.ToChar(i).ToString();
//Get the perfect Image-Size so that Image-Size = String-Size
SizeF size = g.MeasureString(c, myFont);
//Use this to become better Text-Quality on Bitmap.
g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias;
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.PixelOffsetMode = PixelOffsetMode.HighQuality;
//Here we draw the string on the Bitmap
g.DrawString(c, myFont, new SolidBrush(Color.Black), 0, 0);
if (!Directory.Exists("FontBmps"))
Directory.CreateDirectory("FontBmps");
this.Invoke((MethodInvoker)delegate ()
{
pictureBox2.Width = Convert.ToInt32(size.Width);
pictureBox2.Height = Convert.ToInt32(size.Height);
pictureBox2.Image = bmp; // <--- this is working and the picturebox shows the bmp correctly
bmp.Save("FontBmps/" + i + "_" + font + "_" + fontSize + "px_" + fontStyle + ".bmp", ImageFormat.Bmp); // <--- error here: this saves a black square instead of the bmp i see displayed in the picturebox GUI ??
// Even if i save the picturebox itself that too is just a black square instead of the correct image shown in the GUI ??
// now convert the bmp to a HEX array of pixels
for (int h = 0; h < pictureBox2.Height; h++)
{
for (int w = 0; w < pictureBox2.Width; w++)
{
Color colour = (pictureBox2.Image as Bitmap).GetPixel(w, h);
if (colour.R == 0 && colour.G == 0 && colour.B == 0)
{
bits[bitPos] = "1";
}
else
{
bits[bitPos] = "0"; // <-- never hits me, again for some reason the bmp or picturebox is all black pixels data but i see it correctly show in the picturebox GUI ??
}
if (bitPos < 7)
bitPos++;
else
{
//string bitStr = bits.ToString();
//string hex = Convert.ToByte(bitStr, 2).ToString("x2");
//bytes.Add(hex);
bitPos = 0;
for(byte n = 0; n < 8; n++)
{
bits[n] = "0";
}
}
}
}
if (bitPos != 0)
{
// TO DO...
}
});
Thread.Sleep(500); // <--- i have this just to see it displaying the chars but i have removed it with no effect to the issue
}
// now add List to a file in the correct format
foreach (string str in bytes)
{
Console.WriteLine(str);
// TO DO...
}
}
}
}
我认为图像是黑色的,但有些部分是透明的。也就是说,您需要检查 Alpha (Color.A
)。您在图片框中看到的是透明图片框的背景颜色。
您不会在保存的文件中看到透明度,因为 ImageFormat.Bmp
不支持透明度。请尝试 Png
,它支持透明度(并且具有无损压缩)。
或者,您可以使用 Graphics.Clear
将图像设置为您想要的背景颜色(我猜是白色),然后再绘制它。
除此之外,我建议使用 bmp
而不是 (pictureBox2.Image as Bitmap)
,并使用 Bitmap.LockBits
。这将提高性能。
这可能对参考有用:Converting a bitmap to monochrome. See also C# - Faster Alternatives to SetPixel and GetPixel for Bitmaps for Windows Forms App。