【问题标题】:Lines drawn on a large Bitmap are not visible when the image is saved保存图像时,在大位图上绘制的线条不可见
【发布时间】:2020-06-04 20:49:21
【问题描述】:

我创建了一个程序来在选定的图像上绘制方形网格。它适用于分辨率较小的图像,但不适用于大图像。

当图像保存为文件时,似乎所有网格线都不可见。
我正在测试的图像分辨率为3600x4320,可以在link 中显示。

我该如何解决这个问题?

我的代码:

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");
    }
}

结果图片如下(上传分辨率降低)

网格线显示不正确。

【问题讨论】:

    标签: c# winforms graphics drawing gdi+


    【解决方案1】:

    主要问题在这一行:

    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 像素)。在示例代码中,这两个方法接受定义 Pen 颜色和大小的 Colorfloat 参数。

    grp.SmoothingMode:我们这里不需要任何平滑模式,不需要画直线,它会添加清晰可见的抗锯齿,尤其是当保存为JPEG格式的图像时(它会抗锯齿)别名 - 有点,它实际上会破坏颜色 - 这些线条本身)。

    ▶ 您不会处理您创建的任何 Graphics 对象。这对于频繁的图形操作和处理大型位图都非常重要。
    Pen 和 Graphics 对象需要被释放。


    由于尚不清楚是否要生成在两个维度上具有相同行数的网格 - 因此,最有可能的是,具有宽度不等于高度的单元格的网格 - 或者具有平方单元格(这是示例图像似乎显示的内容,而不是代码),我发布了两种绘制两种网格类型的方法:

    第一种方法,宽高行数相同:

    var gridSizeX = (float)image.Width / lines;
    var gridSizeY = (float)image.Height / lines;
    
    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,用于根据位图的最小尺寸定义网格单元。
    然后使用该维度来确定要在另一个维度中绘制多少条线。

    网格大小是在最小维度上计算的:

    var gridSize = (float)Math.Min(image.Width, image.Height) / gridSection; 
    

    Cell 被确定为一个结果:

    var gridStepMin = Math.Min(image.Width, image.Height) / gridSize;
    var gridStepMax = Math.Max(image.Width, image.Height) / gridSize;
    
    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() 方法根据SaveFileDialog.FielName 扩展名选择ImageFormat 类型。

    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);
        if (fileType.Equals("tif")) fileType = "tiff";
        if (fileType.Equals("jpg")) fileType = "jpeg";
        return (ImageFormat)new ImageFormatConverter().ConvertFromString(fileType);
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-10-02
      • 1970-01-01
      • 1970-01-01
      • 2013-12-14
      • 1970-01-01
      相关资源
      最近更新 更多