在SVG或JPEG / PNG内部绘图

时间:2014-09-12 19:50:21

标签: c# .net canvas svg drawing

我正在尝试创建一个可以在SVG或JPG / PNG上绘制的程序。但是,此图仅限于大纲的内部。要获得更好的可视化效果,请查看此图片 - http://www.clker.com/cliparts/c/9/8/9/1237099922676360396kelan_Human_figure.svg

所以,在这里,我们看到一个人形,用黑线勾勒出来。 我需要的基本上是你可以在人体及其头部内部绘制,但是形状之外的所有东西都不应该被着色。

到目前为止,我尝试过使用SharpVector(A Nuget-Package)以及标准画布,但到目前为止我还没有连续播放过。此外,我无法提供任何代码示例,因为它们无论如何都没有任何帮助,至少我是这么认为的!

1 个答案:

答案 0 :(得分:0)

编辑:我的原始答案是:

  

是的,这可以通过SVG图形完成。您需要提取路径   从文件中计算Points和缩放到的图形项目   你的画布。

现在,这很天真。仔细观察SVG格式我不得不说,即使是简单的图像,这也不容易,事实上它是一个相当高的订单......

其余的都是正确的:

  

..然后你可以将它们转换为Region并用它来剪辑   您将用于绘制的Graphics对象。

     

查看有关剪裁区域here on MSDN

的示例      

对于JPEG图像,这不是那么简单。我不确定我是怎么做的;   此刻我正在考虑外面的洪水和XORing   画布的结果,但听起来非常昂贵..

现在,这会让你离开?嗯,我想你需要得到我认为SVG数据将提供的轮廓路径。

这是一个解决方案,您可能会觉得太繁琐或完全没问题:您必须跟踪轮廓并使用跟踪结果来创建剪切区域。跟踪是一项手动任务,但对于示例文件,它可以在大约一分钟内以合理的精度完成。

以下是一些设置最小跟踪程序的例程。你需要一个pictureBox来显示图像为jpg,png或其他; .NET不直接支持svg。将PB设置为缩放并将其锚定在所有侧面。添加几个按钮即可开始..

// We collect the trace data in a list:
List<Point> points = new List<Point>();

// each mouse click adds a point
private void pictureBox1_MouseClick(object sender, MouseEventArgs e)
{  points.Add(e.Location);   pictureBox1.Invalidate();   }

// show all all trace points
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{   if (points.Count < 2) return;
    e.Graphics.DrawCurve(Pens.OrangeRed, points.ToArray());
    foreach (Point p in points) 
        e.Graphics.DrawRectangle(Pens.Red, p.X - 1, p.Y - 1, 3, 3);
}

// always good to have an undo button
private void cb_Undo_Click(object sender, EventArgs e)
{ if (points.Count > 0) { points.RemoveAt(points.Count-1); pictureBox1.Invalidate();} }

// start a new trace by initializing the list
private void cb_NewTrace_Click(object sender, EventArgs e)
{ points = new List<Point>();  pictureBox1.Invalidate();  }

现在我们可以收集跟踪点,我们需要一种方法来保存和加载它们。有很多方法可以做到这一点,尤其是想到了序列化。但是这些简单的功能在短缺方面很难被击败:

void savePoints(List<Point> points, string filename)
{   StringBuilder SB = new StringBuilder();
    foreach (Point P in points) SB.AppendLine(P.X.ToString() + ";" + P.Y.ToString());
    File.WriteAllText(filename, SB.ToString());
}

List<Point> loadPoints(string filename)
{   List<Point> points = new List<Point>();
    var lines = File.ReadAllLines(filename);
    foreach (string l in lines)
    {
        var p = l.Split(';');
        points.Add(new Point(Convert.ToInt16(p[0]), Convert.ToInt16(p[1])));
    }
    return points;
}

使用按钮加载图像,启动跟踪,撤消单击,保存并加载跟踪数据,只需一个按钮即可测试整个图像:

// non-persistent test routine that will draw randomly in the picturebox
private void cb_Test_Click(object sender, EventArgs e)
{
    using (Graphics G = pictureBox1.CreateGraphics())
    {
        // set up the graphicsPath
        GraphicsPath path = new GraphicsPath();
        path.AddCurve(points.ToArray());
        // create the clipping region
        Region region = new Region(path);
        G.SetClip(region, CombineMode.Replace);
        // now we're good to go..
        // note: all drawing is done on the full range of the box!
        G.FillRectangle(Brushes.GhostWhite, pictureBox1.ClientRectangle);
        Random R = new Random();
        int xMax = pictureBox1.ClientSize.Width;
        int yMax = pictureBox1.ClientSize.Height;
        for (int i = 0; i < 1000; i++)
        {
            int x1 = R.Next(xMax);  int y1 = R.Next(yMax);
            int x2 = R.Next(xMax);  int y2 = R.Next(yMax);
            using (Pen pen = new Pen(Color.FromArgb(
                        255, x1 & 255, y1 & 255, x2 * y2 & 255), 10f))
                G.DrawLine(pen, x1, y1, x2, y2);
        }
    }
}

以下是此类曲目的预览,仅包含94个点及其测试填充:

trace points filled trace