本文介绍了在C#中创建不同的画笔图案的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm trying to make something similar to paint. I'm trying to figure out how make different brush styles. Like in Paint 3D you get a certain line fills when using the pen tool vs using the paint brush tool.

我什至不知道从哪里开始.我一天中的大部分时间都在浏览文档,并观看YouTube视频.我比开始时迷路了.我遇到的最接近的东西是线帽,但这绝对不是我想要的.

I have no idea where to even start. I've spent a good portion of the day looking through documentations, and watching YouTube videos. I'm more lost than when I started. The closest thing I came across was line caps, but that's definitely not what I'm looking for.

推荐答案

!!请参见下面的更新!

!!See the UPDATE below!!

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

To help you further here a few points to observe:

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

you need to decide how and when to trigger the drawing; basic options are by time and/or by distance. Usually, the user can set parameters for these often called 'flow' and 'distance'..

,您需要具有透明性的图案文件.您可以制作一些文件,也可以从附近下载许多文件,免费下载许多文件.

you need a pattern file that has transparency. You can either make some or download them from the web where loads of them are around, many for free.

大多数格式为Photoshop Brush格式"abr";如果它们不是太新(< = CS5),则可以使用 abrMate 将它们转换为png文件.

Most are in the Photoshop Brush format 'abr'; if they are not too recent (<=CS5) you can use abrMate to convert them to png files.

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

You can load a set of brushes to an ImageList, set up for large enough size (max 256x256) and 32bpp to allow alpha.

大多数图案都是带有alpha字母的黑色,因此,如果需要颜色,则需要创建当前画笔图像的彩色版本(也许使用ColorMatrix).

Most patterns are black with alpha, so if you want color you need to create a colored version of the current brush image (maybe using a ColorMatrix).

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

You may also want to change its transparency (best also with the ColorMatrix).

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

And you will want to change the size to the current brush size.

更新

做完一些测试后,我不得不撤回最初的假设,即TextureBrush是用于绘制带纹理的笔尖的合适工具.

After doing a few tests I have to retract the original assumption that a TextureBrush is a suitable tool for drawing with textured tips.

可以填充区域,但是对于徒手绘制样式将无法正常工作.原因有很多..:

It is OK for filling areas, but for drawing free-hand style it will not work properly. There are several reasons..:

  • 一个问题是TextureBrush始终会以某种方式 tile 图案,无论是否翻转,这总是看起来像您在揭示一个大的基础图案,而不是用多个笔触堆积涂料.

  • one is that the TextureBrush will always tile the pattern in some way, flipped or not and this will always look like you are revealing one big underlying pattern instead of piling paint with several strokes.

另一个是寻找要填充的区域很成问题.

Another is that finding the area to fill is rather problematic.

提示也可以不是正方形,但是除非您用矩形填充,否则会出现间隙.

Also, tips may or may not be square but unless you fill with a rectangle there will be gaps.

请参见此处举例说明您不想要上班的情况.

See here for an example of what you don't want at work.

解决方案非常简单,上面的大部分内容仍然适用:

The solution is really simple and much of the above still applies:

  • 您所做的几乎是常规的绘图,但最后,您要使用准备好的画笔"图案进行DrawImage.

常规图纸涉及:

  • 一个List<List<Point>> curves包含所有完成的鼠标路径
  • 当前路径的List<Point> curentCurve
  • A List<List<Point>> curves that hold all the finished mouse paths
  • A List<Point> curentCurve for the current path

Paint事件中,绘制所有曲线,如果有任何点,则绘制当前路径.

In the Paint event you draw all the curves and, if it has any points, also the current path.

要绘制带有图案的图形,还必须知道何时绘制哪个图案版本.

For drawing with a pattern, it is necessary to also know when to draw which pattern version.

如果我们确保不泄漏它们,则可以缓存画笔图案..

If we make sure not to leak them we can cache the brush patterns..:

Bitmap brushPattern = null;
List<Tuple<Bitmap,List<Point>>> curves = new List<Tuple<Bitmap,List<Point>>>();
Tuple<Bitmap, List<Point>> curCurve = null;

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

This is a simple/simplistic caching method. For better efficiency you could use a Dictionary<string, Bitmap> with a naming scheme that produces a string from the pattern index, size, color, alpha and maybe a rotation angle; this way each pattern would be stored only once.

以下是工作示例:

一些注意事项:

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

In the MouseDown we create a new current curve:

curCurve = new Tuple<Bitmap, List<Point>>(brushPattern, new List<Point>());
curCurve.Item2.Add(e.Location);

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

In the MouseUp I add the current curve to the curves list:

 curves.Add(new Tuple<Bitmap, List<Point>>(curCurve.Item1, curCurve.Item2.ToList()));

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

Since we want to clear the current curve, we need to copy its points list; this is achieved by the ToList() call!

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

In the MouseMove we simply add a new point to it:

if (e.Button == MouseButtons.Left)
{
    curCurve.Item2.Add(e.Location);
    panel1.Invalidate();
}

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

The Paint goes over all curves including the current one:

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

确保图案绘制在中心.

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

The ListView is set to SmallIcons and its SmallImageList points to a smaller copy of the original ImageList.

重要的是使面板采用双缓冲!以避免闪烁!

It is important to make the Panel Doublebuffered! to avoid flicker!

更新:可以使用PictureboxLabel(对于Autosize=false );都具有开箱即用的DoubleBuffered属性,并且比Panels更好地支持绘图.

Update: Instead of a Panel, which is a Container control and not really meant to draw onto you can use a Picturebox or a Label (with Autosize=false); both have the DoubleBuffered property turned on out of the box and support drawing better than Panels do.

顺便说一句:上面的例子又快又脏,只有200行(未注释).添加笔刷旋转,预览,步进距离,保存按钮并实现笔刷缓存后,它可以达到300行.

Btw: The above quick and dirty example has only 200 (uncommented) lines. Adding brush rotation, preview, a stepping distance, a save button and implementing the brushes cache takes it to 300 lines.

这篇关于在C#中创建不同的画笔图案的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-11 11:20