如何使用画笔在位图上绘画 - C#/.NET
本文关键字:NET 绘画 何使用 画笔 位图 | 更新日期: 2023-09-27 18:36:01
这似乎应该很简单,但我似乎找不到任何方法。 我有一个自定义 WinForms 控件,该控件具有执行一些自定义绘图的重写绘制方法。
我在内存中有一个位图,我想做的只是用 HashBrush 绘制整个内容,但保留 alpha 通道,这样位图的透明部分就不会被绘制。
内存中的位图不是一个简单的形状,因此将其定义为一组路径或任何内容是不可行的。
编辑:为了响应显示代码,绘制例程中有很多代码,所以我只包含一个相关的片段,这是有问题的方法。 此方法从主油漆覆盖调用。 它接受黑色透明蒙版的图像列表并将它们组合成一个,然后它使用 ColorMatrix 更改它创建的组合图像的颜色,允许将其叠加在背景之上。 我想要完成的只是能够在它上面绘制哈希标记。
private void PaintSurface(PaintEventArgs e, Image imgParent, List<Image> surfImgs, Rectangle destRect, ToothSurfaceMaterial material)
{
using (Bitmap bmp = new Bitmap(imgParent.Width, imgParent.Height,
System.Drawing.Imaging.PixelFormat.Format32bppPArgb))
{
using (Graphics g = Graphics.FromImage(bmp))
{
foreach (Image img in surfImgs)
{
g.DrawImage(img, System.Drawing.Point.Empty);
}
}
ColorMatrix matrix = new ColorMatrix(
new float[][] {
new float[] { 0, 0, 0, 0, 0},
new float[] { 0, 0, 0, 0, 0},
new float[] { 0, 0, 0, 0, 0},
new float[] { 0, 0, 0, 0.7f, 0},
new float[] { material.R / 255.0f,
material.G / 255.0f,
material.B / 255.0f,
0, 1}
});
ImageAttributes imageAttr = new ImageAttributes();
imageAttr.SetColorMatrix(matrix);
Rectangle r = GetSizedRect(imgParent, destRect);
e.Graphics.DrawImage(bmp,
r,
0,
0,
bmp.Width,
bmp.Height,
GraphicsUnit.Pixel, imageAttr);
}
}
我最终使用的解决方案是以下方法。 首先,我将各个蒙版组合成一个,然后创建一个新的位图并使用 HatchBrush 绘制整个蒙版,最后遍历蒙版并根据蒙版在新生成的位图上设置 alpha 值。
private Bitmap GenerateSurface(Image imgParent, List<Image> surfImgs, ToothSurfaceMaterial material)
{
Bitmap mask = new Bitmap(imgParent.Width, imgParent.Height,
System.Drawing.Imaging.PixelFormat.Format32bppPArgb);
using (Graphics g = Graphics.FromImage(mask))
{
foreach (Image img in surfImgs)
{
g.DrawImage(img, System.Drawing.Point.Empty);
}
}
Bitmap output = new Bitmap(mask.Width, mask.Height,
System.Drawing.Imaging.PixelFormat.Format32bppPArgb);
using (Graphics g = Graphics.FromImage(output))
{
if (material.HatchStyle != null)
{
HatchBrush hb = new HatchBrush((HatchStyle)material.HatchStyle, material.FgColor, material.BgColor);
g.FillRectangle(hb, new Rectangle(0, 0, output.Width, output.Height));
}
else
{
SolidBrush sb = new SolidBrush(material.FgColor);
g.FillRectangle(sb, new Rectangle(0, 0, output.Width, output.Height));
}
}
var rect = new Rectangle(0, 0, output.Width, output.Height);
var bitsMask = mask.LockBits(rect, ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
var bitsOutput = output.LockBits(rect, ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
unsafe
{
int offset = 0;
for (int y = 0; y < mask.Height; y++)
{
byte* ptrMask = (byte*)bitsMask.Scan0 + y * bitsMask.Stride;
byte* ptrOutput = (byte*)bitsOutput.Scan0 + y * bitsOutput.Stride;
for (int x = 0; x < mask.Width; x++)
{
offset = 4 * x + 3;
ptrOutput[offset] = (byte)(ptrMask[offset] * 0.7);
}
}
}
mask.UnlockBits(bitsMask);
output.UnlockBits(bitsOutput);
return output;
}
我认为你不需要任何矫枉过正ColorMatrix
,你只需要一个ColorMap
,这是可能不适合你的要求的代码,但应该给你一个想法。那是因为我可能不太了解你的问题,如果你有任何问题,只需发表一些评论,我会尽力改进答案:
ImageAttributes imgA = new ImageAttributes();
ColorMap cm = new ColorMap();
cm.OldColor = Color.Black
cm.NewColor = Color.FromArgb((byte)(0.7*255), Color.Green);
imgA.SetRemapTable(new ColorMap[] {cm });
GraphicsUnit gu = GraphicsUnit.Pixel;
g.DrawImage(imageToDraw,new Point[]{Point.Empty,
new Point(backImage.Width/2,0),
new Point(0,backImage.Height/2)},
Rectangle.Round(imageToDraw.GetBounds(ref gu)),
GraphicsUnit.Pixel, imgA);
new Point[]
是一个由 3 个Points
组成的数组,用于定位目标矩形。上面的代码用于在backImage
顶部绘制imageToDraw
,并将Black
的颜色转换为带有Opacity = 70%
的颜色Green
。这就是你想要完成你的代码。
更新
这可能是你想要的,事实上你的代码并没有显示你想要什么,它只是显示你拥有的东西,它现在没有实现与你的问题相关的任何内容。我从您在问题中的第一个描述中推断出这一点。输入是具有背景颜色(稍后将部分透明)的图像正在Black
。现在,您想要的输出是一张图像,其中所有非黑色区域都用HatchBrush
绘制。然后,将处理此输出以将Black
背景转换为partially transparent
背景。
public void PaintHatchBrush(Bitmap input, HatchBrush brush){
using(Graphics g = Graphics.FromImage(input)){
g.Clip = GetForegroundRegion(input, Color.Black);
GraphicsUnit gu = GraphicsUnit.Pixel;
g.FillRectangle(brush, input.GetBounds(ref gu));
}
}
//This is implemented using `GetPixel` which is not fast, but it gives you the idea.
public Region GetForegroundRegion(Bitmap input, Color backColor){
GraphicsPath gp = new GraphicsPath();
Rectangle rect = Rectangle.Empty;
bool jumpedIn = false;
for (int i = 0; i < bm.Height; i++) {
for (int j = 0; j < bm.Width; j++) {
Color c = bm.GetPixel(j, i);
if (c != backColor&&!jumpedIn) {
rect = new Rectangle(j, i, 1, 1);
jumpedIn = true;
}
if (jumpedIn && (c == backColor || j == bm.Width - 1)) {
rect.Width = j - rect.Left;
gp.AddRectangle(rect);
jumpedIn = false;
}
}
}
return new Region(gp);
}
//Usage
HatchBrush brush = new HatchBrush(HatchStyle.Percent30, Color.Green, Color.Yellow);
PaintHatchBrush(yourImage, brush);
//then yourImage will have HatchBrush painted on the surface leaving the Black background intact.
//This image will be used in the next process to turn the Black background into 70%
//opacity background as you did using ColorMatrix (or more simply using ColorMap as I posted previously)