如何使用画笔在位图上绘画 - 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);
        }
    }

如何使用画笔在位图上绘画 - C#/.NET

我最终使用的解决方案是以下方法。 首先,我将各个蒙版组合成一个,然后创建一个新的位图并使用 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)