在c#中创建不同的画笔模式

roc*_*cky 2 c# picturebox winforms

我正在尝试制作类似油漆的东西.我想弄清楚如何制作不同的画笔样式.就像在Paint 3D中一样,当使用钢笔工具和使用油漆刷工具时,你会得到一定的线条填充.

在此输入图像描述

我不知道从哪里开始.我花了很多时间查看文档,观看YouTube视频.我比起初时更迷茫.我遇到的最接近的是线帽,但这绝对不是我想要的.

TaW*_*TaW 7

!!见下面的更新!!

Hans的链接应该指向正确的方向,即指向TextureBrushes.

为了帮助您进一步观察以下几点:

  • TextureBrush是画笔,而不是笔.所以你不能沿着一条路径,就像沿着那条曲线画出的鼠标动作一样.相反,您需要找到一个用刷子填充的区域.

  • 这也意味着 你需要决定如何以及何时触发绘图; 基本选项是按时间和/或按距离.通常,用户可以为这些通常称为"流量"和"距离"的参数设置参数.

  • 您可以继续将形状添加到GraphicsPath并填充该路径,而不是填充简单的形状并绘制其中的许多形状.

  • 创建TextureBrush 你需要一个具有透明度的模式文件.您可以制作一些或从网上下载它们,其中许多是免费的.

  • 大多数都是Photoshop画笔格式'abr'; 如果它们不是太新(<= CS5),您可以使用abrMate将它们转换为png文件.

  • 您可以将一组画笔加载到ImageList,设置足够大的尺寸(最大256x256)和32bpp以允许alpha.

  • 大多数图案都是黑色的alpha,所以如果你想要颜色,你需要创建当前画笔图像的彩色版本(可能使用ColorMatrix).

  • 您可能还想更改其透明度(最好也使用ColorMatrix).

  • 并且您需要将大小更改为当前画笔大小.


更新

在做了一些测试后,我不得不收回一个原始的假设,即TextureBrush是一个适合绘制纹理提示的工具.

填充区域是可以的,但是为了绘制自由式样式,它将无法正常工作.有几个原因..:

  • 一个是TextureBrush将始终以某种方式平铺图案,翻转或不翻转,这看起来总是看起来像是在显示一个大的底层图案而不是用几个笔划打桩.

  • 另一个是找到要填补的区域是相当有问题的.

  • 此外,提示可能是也可能不是正方形,但除非您填充矩形,否则会有间隙.

这里为你的内容的示例不做希望在工作中.

解决方案非常简单,上述大部分仍然适用:

  • 你做的是非常规则的绘画,但最后,你DrawImage用准备好的'画笔'模式.

定期绘图涉及:

  • List<List<Point>> curves包含所有已完成鼠标路径的A.
  • A List<Point> curentCurve为当前路径

Paint事件中,你画的所有的曲线,如果有任何点,也是当前路径.

对于使用图案绘图,还必须知道何时绘制哪个图案版本.

如果我们确保不泄漏它们,我们可以缓存画笔模式..:

Bitmap brushPattern = null;
List<Tuple<Bitmap,List<Point>>> curves = new List<Tuple<Bitmap,List<Point>>>();
Tuple<Bitmap, List<Point>> curCurve = null;
Run Code Online (Sandbox Code Playgroud)

这是一种简单/简单的缓存方法.为了提高效率,您可以使用 Dictionary<string, Bitmap>命名方案,该方案根据模式索引,大小,颜色,alpha和旋转角度生成字符串; 这样每个模式只能存储一次.

这是一个工作的例子:

在此输入图像描述

几点说明:

在MouseDown中,我们创建一个新的当前曲线:

curCurve = new Tuple<Bitmap, List<Point>>(brushPattern, new List<Point>());
curCurve.Item2.Add(e.Location);
Run Code Online (Sandbox Code Playgroud)

在MouseUp中,我将当前曲线添加到曲线列表中:

 curves.Add(new Tuple<Bitmap, List<Point>>(curCurve.Item1, curCurve.Item2.ToList()));
Run Code Online (Sandbox Code Playgroud)

由于我们要清除当前曲线,我们需要复制其点列表; 这是通过ToList()电话实现的!

在MouseMove中,我们只需添加一个新点:

if (e.Button == MouseButtons.Left)
{
    curCurve.Item2.Add(e.Location);
    panel1.Invalidate();
}
Run Code Online (Sandbox Code Playgroud)

Paint遍历所有曲线,包括当前曲线:

for (int c = 0; c < curves.Count; c++)
{
    e.Graphics.TranslateTransform(-curves[c].Item1.Width / 2, -curves[c].Item1.Height / 2);
    foreach (var p in curves[c].Item2)
        e.Graphics.DrawImage(curves[c].Item1, p);
    e.Graphics.ResetTransform();
}
if (curCurve != null && curCurve.Item2.Count > 0)
{
    e.Graphics.TranslateTransform(-curCurve.Item1.Width / 2, -curCurve.Item1.Height / 2);

    foreach (var p in curCurve.Item2)
        e.Graphics.DrawImage(curCurve.Item1, p);
    e.Graphics.ResetTransform();
}
Run Code Online (Sandbox Code Playgroud)

它确保图案以中心绘制.

ListView设置为SmallIcons,其SmallImageList指向原始ImageList的较小副本.

使Panel Doublebuffered非常重要!避免闪烁!

顺便说一句:上面这个快速而肮脏的例子只有200行(未注释).添加画笔旋转,预览,步进距离,保存按钮和实现画笔缓存可将其转换为300行.