3

构建一个小绘图程序,并尝试合并图层的概念。

我正在使用 PictureBox 控件来显示图像,并从 PictureBox 显示的图像中获取 Graphics 对象并绘制到该对象。

我的问题是我试图弄清楚如何绘制到覆盖在图片框顶部的新 Graphics 对象,并且能够在将原始图像吸收到图形中的情况下获得新绘制的图像。

如果我这样做:

Graphics gr = Graphics.FromImage(myPictureBox.image);
gr.DrawRectangle(blah blah)

...我正在编辑图片框中的原始图像。我想要一种方法来仅捕获正在绘制的新内容作为单独的图像,但仍将其显示为覆盖在已经存在的内容之上。

谁能指出我正确的方向?谢谢!

4

4 回答 4

4

我估计会使用透明控件并进行一些修改,以便它可以用作图像层:

http://www.codeproject.com/Articles/26878/Making-Transparent-Controls-No-Flickering

可能是这样的(根据需要进行任何修改)。

class LayerControl : UserControl
{
    private Image image;
    private Graphics graphics;

    public LayerControl(int width, int height)
    {
        this.Width = width;
        this.Height = height;

        image = new Bitmap(width, height);

        graphics = Graphics.FromImage(image);

        // Set style for control
        SetStyle(ControlStyles.OptimizedDoubleBuffer |
                ControlStyles.AllPaintingInWmPaint |
                ControlStyles.UserPaint, true);
    }

    // this function will draw your image
    protected override void OnPaint(PaintEventArgs e)
    {
        var bitMap = new Bitmap(image);
        // by default the background color for bitmap is white
        // you can modify this to follow your image background 
        // or create a new Property so it can dynamically assigned
        bitMap.MakeTransparent(Color.White);

        image = bitMap;

        Graphics g = e.Graphics;
        g.SmoothingMode = SmoothingMode.AntiAlias;
        g.PixelOffsetMode = PixelOffsetMode.HighQuality;
        g.CompositingQuality = CompositingQuality.GammaCorrected;

        float[][] mtxItens = {
            new float[] {1,0,0,0,0},
            new float[] {0,1,0,0,0},
            new float[] {0,0,1,0,0},
            new float[] {0,0,0,1,0},
            new float[] {0,0,0,0,1}};

        ColorMatrix colorMatrix = new ColorMatrix(mtxItens);

        ImageAttributes imgAtb = new ImageAttributes();
        imgAtb.SetColorMatrix(
            colorMatrix,
            ColorMatrixFlag.Default,
            ColorAdjustType.Bitmap);

        g.DrawImage(image,
                    ClientRectangle,
                    0.0f,
                    0.0f,
                    image.Width,
                    image.Height,
                    GraphicsUnit.Pixel,
                    imgAtb);
    }

    // this function will grab the background image to the control it self
    protected override void OnPaintBackground(PaintEventArgs e)
    {
        base.OnPaintBackground(e);
        Graphics g = e.Graphics;

        if (Parent != null)
        {
            BackColor = Color.Transparent;
            int index = Parent.Controls.GetChildIndex(this);

            for (int i = Parent.Controls.Count - 1; i > index; i--)
            {
                Control c = Parent.Controls[i];
                if (c.Bounds.IntersectsWith(Bounds) && c.Visible)
                {
                    Bitmap bmp = new Bitmap(c.Width, c.Height, g);
                    c.DrawToBitmap(bmp, c.ClientRectangle);

                    g.TranslateTransform(c.Left - Left, c.Top - Top);
                    g.DrawImageUnscaled(bmp, Point.Empty);
                    g.TranslateTransform(Left - c.Left, Top - c.Top);
                    bmp.Dispose();
                }
            }
        }
        else
        {
            g.Clear(Parent.BackColor);
            g.FillRectangle(new SolidBrush(Color.FromArgb(255, Color.Transparent)), this.ClientRectangle);
        }
    }

    // simple drawing circle function
    public void DrawCircles()
    {
        using (Brush b = new SolidBrush(Color.Red))
        {
            using (Pen p = new Pen(Color.Green, 3))
            {
                this.graphics.DrawEllipse(p, 25, 25, 20, 20);
            }
        }
    }

    // simple drawing rectable function
    public void DrawRectangle()
    {
        using (Brush b = new SolidBrush(Color.Red))
        {
            using (Pen p = new Pen(Color.Red, 3))
            {
                this.graphics.DrawRectangle(p, 50, 50, 40, 40);
            }
        }
    }

    // Layer control image property
    public Image Image
    {
        get
        {
            return image;
        }
        set
        {
            image = value;
            // this will make the control to be redrawn
            this.Invalidate();
        }
    }
}

示例如何使用它:

LayerControl lc = new LayerControl(100, 100);
lc.Location = new Point(0, 0);
lc.DrawRectangle();

LayerControl lc2 = new LayerControl(100, 100);
lc2.Location = new Point(0, 0);
lc2.DrawCircles();

LayerControl lc3 = new LayerControl(100, 100);
lc3.Location = new Point(0, 0);
lc3.Image = new Bitmap(@"<Image Path>");

// adding control
this.Controls.Add(dc);
this.Controls.Add(dc2);
this.Controls.Add(dc3);

使用这种方法,您可以拥有多个可以相互重叠的图层(由于它具有透明度功能)。

如果要将其添加到 PictureBox 顶部,请确保重新排序控件。图层控件应添加在您的 PictureBox 控件之前。

// adding control
this.Controls.Clear();
this.Controls.Add(dc);
this.Controls.Add(dc2);
this.Controls.Add(dc3);
this.Controls.Add(PictureBox1);

希望它有所帮助。

于 2012-10-03T09:07:47.750 回答
4

工作正常的示例代码 - 获取虚拟图像并将原始图像与自定义文本分层

public void LayerImage(System.Drawing.Image Current, int LayerOpacity)
{
    Bitmap bitmap = new Bitmap(Current);        
    int h = bitmap.Height;
    int w = bitmap.Width;
    Bitmap backg = new Bitmap(w, h + 20);
    Graphics g = null;
    try
    {
        g = Graphics.FromImage(backg);
        g.Clear(Color.White);
        Font font = new Font("Arial", 12, FontStyle.Bold, GraphicsUnit.Pixel);
        RectangleF rectf = new RectangleF(70, 90, 90, 50);
        Color color = Color.FromArgb(255, 128, 128, 128);
        Point atpoint = new Point(backg.Width / 2, backg.Height - 10);
        SolidBrush brush = new SolidBrush(color);
        StringFormat sf = new StringFormat();
        sf.Alignment = StringAlignment.Center;
        sf.LineAlignment = StringAlignment.Center;
        g.DrawString("BRAND AMBASSADOR", font, brush, atpoint, sf);
        g.Dispose();
        MemoryStream m = new MemoryStream();
        backg.Save(m, System.Drawing.Imaging.ImageFormat.Jpeg);
    }
    catch { }

    Color pixel = new Color();

    for (int x = 0; x < bitmap.Width; x++)
    {
        for (int y = 0; y < bitmap.Height; y++)
        {
            pixel = bitmap.GetPixel(x, y);
            backg.SetPixel(x, y, Color.FromArgb(LayerOpacity, pixel));
        }
    }
    MemoryStream m1 = new MemoryStream();
    backg.Save(m1, System.Drawing.Imaging.ImageFormat.Jpeg);
    m1.WriteTo(Response.OutputStream);
    m1.Dispose();
    base.Dispose();
}
于 2014-04-24T08:43:31.703 回答
1

得到它的工作,也许我在最初的问题中不够清楚。

基本上我最终所做的是将每个图层存储为一个单独的 Image 对象,然后只需连接到我的控件的 OnPaint 方法并手动按顺序绘制图形,而不是仅仅绘制到 PictureBox.Image。奇迹般有效!

于 2012-10-05T20:25:06.597 回答
0

.NET 绘图库的图形功能很简单。它们的主要目的是直接绘制 GUI。如果您想要分层、alpha 透明度或高级过滤器,那么您应该使用 3rd 方库或滚动您自己的绘图代码。

于 2012-10-03T06:24:42.530 回答