我创建了一个程序,可以在所选图像上绘制正方形网格。它适用于分辨率较低的图像,但不适用于较大的图像。将图像另存为文件时,所有网格线都没有出现。我正在测试的图像分辨率为3600x4320
,可以在link中显示。如何解决此问题?
我的代码:
/// <summary>
/// Draw grids
/// </summary>
/// <param name="n">Nof square to draw in width</param>
/// <param name="imgPath">Source image</param>
/// <returns></returns>
Image drawGrid(int n, string imgPath)
{
Image img = Image.FromFile(imgPath);
Graphics grp = Graphics.FromImage(img);
grp.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
float m = img.Width * 1f / n;
for (int i = 1; i < n; i++)
{
var x = new PointF(i * m, 0);
var y = new PointF(i * m, img.Height);
grp.DrawLine(Pens.Red, x, y);
}
for (int i = 1; i <= (int)(this.Height / m); i++)
{
var x = new PointF(0, i * m);
var y = new PointF(img.Width, i * m);
grp.DrawLine(new Pen(Color.Red, 5f), x, y);
}
return img;
}
void BtnExportClick(object sender, EventArgs e)
{
if(saveFileDialog1.ShowDialog() == DialogResult.OK)
{
int n = (int)numericUpDown1.Value;
drawGrid(n, txtImagePath.Text).Save(saveFileDialog1.FileName, System.Drawing.Imaging.ImageFormat.Jpeg);
MessageBox.Show("Done");
}
}
结果图像在下面(分辨率降低为上传)
网格线未正确显示。
主要问题在此行:
for (int i = 1; i <= (int)(this.Height / m); i++)
►this.Height
显然不是您想要编写的内容,我们将其替换为Image.Height
►grp.DrawLine(Pens.Red, x, y);
和grp.DrawLine(new Pen(Color.Red, 5f), x, y);
将绘制不同大小的线(1和5像素)。在示例代码中,这两种方法接受Color
和float
参数,它们定义了Pen的颜色和大小。
►grp.SmoothingMode
:我们在这里不需要任何平滑模式,不需要绘制直线,它会添加清晰可见的抗锯齿,尤其是在将图像保存为JPEG格式时(抗锯齿) -实际上,它会弄乱颜色-这些线条本身)。
►您不会丢弃创建的任何Graphics对象。这对于频繁的图形操作以及使用大型位图时都非常重要。笔和图形对象需要处理。
因为尚不清楚您是否要生成一个在两个维度上都具有相同行数的网格-因此,最可能是其单元格的宽度不等于高度的网格-或一个正方形的网格单元格(这是示例图像似乎显示的内容,而不是代码),我发布了两种绘制两种网格类型的方法:
第一种方法,宽度和高度都相同的行数:
private Image DrawGridLines(int lines, string imgPath, Color penColor, float penSize)
{
var image = Image.FromStream(new MemoryStream(File.ReadAllBytes(imgPath)), true);
using (var g = Graphics.FromImage(image)) {
g.PixelOffsetMode = PixelOffsetMode.Half;
var gridSizeX = (float)image.Width / lines;
var gridSizeY = (float)image.Height / lines;
for (int i = 1; i < lines; i++) {
var pointX1 = new PointF(0, i * gridSizeY);
var pointX2 = new PointF(image.Width, i * gridSizeY);
var pointY1 = new PointF(i * gridSizeX, 0);
var pointY2 = new PointF(i * gridSizeX, image.Height);
using (var pen = new Pen(penColor, penSize)) {
g.DrawLine(pen, pointX1, pointX2);
g.DrawLine(pen, pointY1, pointY2);
}
}
return image;
}
}
第二种方法,绘制一个正方形网格。整数值gridSection
用于基于位图的最小尺寸定义网格单元。然后使用该尺寸确定在另一个尺寸中要绘制多少条线。
private Image DrawSquaredGrid(int gridSection, string imgPath, Color penColor, float penSize)
{
var image = Image.FromStream(new MemoryStream(File.ReadAllBytes(imgPath)), true);
using (var g = Graphics.FromImage(image)) {
g.PixelOffsetMode = PixelOffsetMode.Half;
var gridSize = (float)Math.Min(image.Width, image.Height) / gridSection;
var gridStepMin = Math.Min(image.Width, image.Height) / gridSize;
var gridStepMax = Math.Max(image.Width, image.Height) / gridSize;
for (int i = 1; i < gridStepMin; i++) {
var pointY1 = new PointF(i * gridSize, 0);
var pointY2 = new PointF(i * gridSize, image.Height);
using (var pen = new Pen(penColor, penSize)) {
g.DrawLine(pen, pointY1, pointY2);
}
}
for (int i = 1; i < gridStepMax; i++) {
var pointX1 = new PointF(0, i * gridSize);
var pointX2 = new PointF(image.Width, i * gridSize);
using (var pen = new Pen(penColor, penSize)) {
g.DrawLine(pen, pointX1, pointX2);
}
}
return image;
}
}
SaveFileDialog被重构以允许多种图像格式。并基于选择调用一种绘制方法(在示例代码中,使用CheckBox(chkSquared
)选择一种Grid类型)。您可以添加更多格式,ImageFormatFromFileName()
方法根据ImageFormat
扩展名选择SaveFileDialog.FielName
类型。
private void BtnExportClick(object sender, EventArgs e)
{
string imagePath = [Some Path];
using (var sfd = new SaveFileDialog()) {
sfd.Filter = "PNG Image (*.png)|*.png|TIFF Image (*.tif)|*.tif|JPEG Image (*.jpg)|*.jpg";
sfd.RestoreDirectory = true;
sfd.AddExtension = true;
if (sfd.ShowDialog() == DialogResult.OK) {
Image image = null;
if (chkSquared.Checked) {
image = DrawSquaredGrid((int)numericUpDown1.Value, imagePath, Color.Red, 5.0f);
}
else {
image = DrawGridLines((int)numericUpDown1.Value, imagePath, Color.Red, 5.0f);
}
image.Save(sfd.FileName, ImageFormatFromFileName(sfd.FileName));
MessageBox.Show("Done");
image.Dispose();
}
}
}
private ImageFormat ImageFormatFromFileName(string fileName)
{
string fileType = Path.GetExtension(fileName).Remove(0, 1).ToLower();
if (fileType.Equals("tif")) fileType = "tiff";
if (fileType.Equals("jpg")) fileType = "jpeg";
return (ImageFormat)new ImageFormatConverter().ConvertFromString(fileType);
}