Вопрос:
Я пытаюсь сделать что-то похожее на краску. Я пытаюсь понять, как создавать разные стили кистей. Как и в Paint 3D, вы получаете определенную линию заливки при использовании инструмента пера против использования инструмента кисти.
Я даже не знаю, с чего начать. Я потратил большую часть дня на просмотр документов и просмотр видео на YouTube. Я потерял больше, чем когда начал. Самое близкое, что я натолкнулся, это штриховки, но это определенно не то, что я ищу.
Лучший ответ:
!! Смотрите ОБНОВЛЕНИЕ ниже !!
Ссылка Ганса должна указывать вам правильное направление, а именно на TextureBrushes.
Чтобы помочь вам в дальнейшем здесь несколько моментов для наблюдения:
-
TextureBrush – это кисть, а не ручка. Таким образом, вы не можете следовать по пути, как движения мыши, чтобы рисовать вдоль этой кривой. Вместо этого вам нужно найти область для заполнения кистью.
-
Это также подразумевает, что вам нужно решить, как и когда вызывать рисунок; Основные варианты по времени и/или по расстоянию. Обычно пользователь может установить параметры для этих часто называемых “поток” и “расстояние”.
-
Вместо того, чтобы заполнять простую форму и рисовать многие из них, вы можете продолжать добавлять формы в GraphicsPath и заполнять этот путь.
-
Чтобы создать TextureBrush вам нужен файл шаблона, который имеет прозрачность. Вы можете сделать некоторые или скачать их из Интернета, где их много, многие бесплатно.
-
Большинство из них в формате кисти Photoshop ‘abr’; если они не слишком свежие (<= CS5), вы можете использовать abrMate для преобразования их в png файлы.
-
Вы можете загрузить набор кистей в ImageList, настроив его на достаточно большой размер (максимум 256×256) и 32bpp, чтобы разрешить альфа.
-
Большинство рисунков чёрного цвета с альфа-каналом, поэтому если вам нужен цвет, вам нужно создать цветную версию текущего изображения кисти (возможно, с помощью ColorMatrix).
-
Вы также можете изменить прозрачность (лучше всего с ColorMatrix).
-
И вы захотите изменить размер на текущий размер кисти.
Обновить
После нескольких тестов я должен отказаться от первоначального предположения, что TextureBrush является подходящим инструментом для рисования с текстурированными кончиками.
Это нормально для заполнения областей, но для рисования стиля от руки это не будет работать должным образом. Есть несколько причин..:
-
один является то, что TextureBrush всегда плитка шаблон в некотором роде, переворачивается или нет, и это всегда будет выглядеть, как вы показательны один большой базовый шаблон вместо укладки краски с несколькими штрихами.
-
Другое дело, что найти область для заполнения довольно проблематично.
-
Кроме того, подсказки могут быть или не быть квадратными, но если вы не заполните прямоугольник, будут пробелы.
Смотрите здесь пример того, что вы не хотите на работе.
Решение действительно простое, и многое из вышеперечисленного все еще применяется:
- То, что вы делаете, это в значительной степени регулярное рисование, но в конце вы делаете DrawImage с подготовленным “кистевым” рисунком.
Обычный рисунок включает в себя:
- List<List<Point>> curves которые содержат все готовые пути мыши
- 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;
Это простой/упрощенный метод кэширования. Для повышения эффективности вы можете использовать Dictionary<string, Bitmap> со схемой именования, которая создает строку из индекса шаблона, размера, цвета, альфы и, возможно, угла поворота; таким образом, каждый шаблон будет сохранен только один раз.
Вот пример на работе:
Несколько заметок:
В MouseDown мы создаем новую текущую кривую:
curCurve = new Tuple<Bitmap, List<Point>>(brushPattern, new List<Point>()); curCurve.Item2.Add(e.Location);
В MouseUp я добавляю текущую кривую в список кривых:
curves.Add(new Tuple<Bitmap, List<Point>>(curCurve.Item1, curCurve.Item2.ToList()));
Поскольку мы хотим очистить текущую кривую, нам нужно скопировать ее список точек; это достигается с помощью ToList() !
В MouseMove мы просто добавляем новую точку:
if (e.Button == MouseButtons.Left) { curCurve.Item2.Add(e.Location); panel1.Invalidate(); }
Краска проходит по всем кривым, включая текущую:
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.
Важно сделать панель Doublebuffered! чтобы избежать мерцания!
Обновление: вместо Panel, которая является элементом Panel Container и на самом деле не предназначена для рисования, вы можете использовать Picturebox или Label (с Autosize=false); оба имеют свойство DoubleBuffered из коробки, и поддерживают рисование лучше, чем Panels.
Кстати: приведенный выше быстрый и грязный пример содержит только 200 (некомментированных) строк. Добавление поворота кисти, предварительного просмотра, шага перехода, кнопки сохранения и реализации кэша кистей занимает до 300 строк.