How can i fill part of image with color?

后端 未结 1 1001
一生所求
一生所求 2020-12-03 19:52

I have image which i add in my form.How can i fill part of image?

I have this

\"I

W

相关标签:
1条回答
  • 2020-12-03 20:26

    To floodfill an area you need a foodfill routine and very little else.

    See this example:

    It uses two pictureboxes, also a label to display the chosen color.

    And two mouse click events, one to pick the color:

    private void pictureBoxPalette_MouseClick(object sender, MouseEventArgs e)
    {
        Point sPt = scaledPoint(pictureBoxPalette, e.Location);
        lbl_color.BackColor = ((Bitmap)pictureBoxPalette.Image).GetPixel(sPt.X, sPt.Y);
    }
    

    ..and one to call the fill:

    private void pictureBoxTgt_MouseClick(object sender, MouseEventArgs e)
    {
        Point sPt = scaledPoint(pictureBoxTgt, e.Location);
        Bitmap bmp = (Bitmap)pictureBoxTgt.Image;
        Color c0 = bmp.GetPixel(sPt.X, sPt.Y); 
        Fill4(bmp, sPt, c0, lbl_color.BackColor);
        pictureBoxTgt.Image = bmp;
    }
    

    The Floodfill routine is taken from this post; it is basically a direct implementation of a wikipedia algorithm..:

    static void Fill4(Bitmap bmp, Point pt, Color c0, Color c1)
    {
        Color cx = bmp.GetPixel(pt.X, pt.Y);
        if (cx.GetBrightness() < 0.01f) return;  // optional, to prevent filling a black grid
        Rectangle bmpRect = new Rectangle(Point.Empty, bmp.Size);
        Stack<Point> stack = new Stack<Point>();
        int x0 = pt.X;
        int y0 = pt.Y;
    
        stack.Push(new Point(x0, y0) );
        while (stack.Any() )
        {
            Point p = stack.Pop();
            if (!bmpRect.Contains(p)) continue;
            cx = bmp.GetPixel(p.X, p.Y);
            if (cx == c0)
            {
                bmp.SetPixel(p.X, p.Y, c1);
                stack.Push(new Point(p.X, p.Y + 1));
                stack.Push(new Point(p.X, p.Y - 1));
                stack.Push(new Point(p.X + 1, p.Y));
                stack.Push(new Point(p.X - 1, p.Y));
            }
        }
    }
    

    Update

    I have updated the code to include a function that will scale a mouse click location to an image pixel point; now it will work with SizeMode=StretchImage as well, so you can work on the whole image..

    static Point scaledPoint(PictureBox pb, Point pt)
    {
        float scaleX = 1f * pb.Image.Width / pb.ClientSize.Width;
        float scaleY = 1f * pb.Image.Height / pb.ClientSize.Height;
        return  new Point((int)(pt.X * scaleX), (int)(pt.Y * scaleY));
    }
    

    Of course you can then save the Image.

    Note that your original image is 4bpp and must be converted to 24bpp or better before coloring..

    Also note that for SizeMode=Zoom the calculations are a little more involved. Here is an example that should work with any SizeMode.:

    static Point scaledPoint(PictureBox pbox, Point pt)
    {
        Size si = pbox.Image.Size;
        Size sp = pbox.ClientSize;
        int left = 0;
        int top = 0;
    
        if (pbox.SizeMode == PictureBoxSizeMode.Normal ||
            pbox.SizeMode == PictureBoxSizeMode.AutoSize) return pt;
        if (pbox.SizeMode == PictureBoxSizeMode.CenterImage)
        {
            left = (sp.Width - si.Width) / 2;
            top = (sp.Height - si.Height) / 2;
            return new Point(pt.X - left, pt.Y - top);
        }                   
        if (pbox.SizeMode == PictureBoxSizeMode.Zoom)
        {
            if (1f * si.Width / si.Height < 1f * sp.Width / sp.Height)
                left = (sp.Width - si.Width * sp.Height / si.Height) / 2;
            else
                top = (sp.Height - si.Height * sp.Width / si.Width) / 2;
        }
    
        pt = new Point(pt.X  - left, pt.Y - top);
        float scaleX = 1f * pbox.Image.Width / (pbox.ClientSize.Width - 2 * left) ;
        float scaleY = 1f * pbox.Image.Height / (pbox.ClientSize.Height - 2 * top);
        return new Point((int)(pt.X * scaleX), (int)(pt.Y * scaleY));
    }
    
    0 讨论(0)
提交回复
热议问题