1
votes

I have 3 layers (control "LayerControl" from here): image layer, drawing layer, and selection rectangle layer.

ImgEditor is a form for editing images (i'm making screenshooter and i want to add an image editor to it).

Layers are sorted in that order:

  1. l3 - rectangle layer
  2. l2 - drawing layer
  3. l - image layer

Because l3 is top control, i must use callbacks MouseDown, MouseMove and MouseUp on it and then draw on l2 (drawing layer). But when i'm trying to draw, i'm getting just nothing. Or, if i place l2 as the top layer, i'm getting this.

My code:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Imaging;
using System.Drawing.Drawing2D;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace SSTool
{
    public partial class ImgEditor : Form
    {
        private Graphics g;
        public Image _i;
        public Brush gb = new SolidBrush(Color.Red);
        public bool md = false;
        public LayerControl l;
        public LayerControl l2;
        public LayerControl l3;
        public Point? _Previous = null;

        public ImgEditor(Image i, Rectangle r)
        {
            //l - main image
            //l2 - drawing layer
            //l3 - rectangle layer
            InitializeComponent();
            l = new LayerControl(i.Size);
            l2 = new LayerControl(i.Size);
            l3 = new LayerControl(i.Size);
            this.Controls.Add(l3);
            this.Controls.Add(l2);
            this.Controls.Add(l);
            l.Dock = DockStyle.Fill;
            l2.Dock = DockStyle.Fill;
            l3.Dock = DockStyle.Fill;
            l2.Image = new Bitmap(i.Size.Width, i.Size.Height);
            l3.MouseDown += new MouseEventHandler(l3_MouseDown);
            l3.MouseMove += new MouseEventHandler(l3_MouseMove);
            l3.MouseUp += new MouseEventHandler(l3_MouseUp);
            _i = i;
            l.Image = _i;
            this.Size = _i.Size;
            g = Graphics.FromImage(l3.Image);
            g.Clear(Color.Transparent);
            Pen p = new Pen(Color.FromArgb(180, 255, 0, 0));
            Brush sb = new SolidBrush(Color.FromArgb(128, 211, 211, 211));
            g.FillRectangle(sb, new Rectangle(0, 0, i.Size.Width, r.Location.Y)); //TOP
            g.FillRectangle(sb, new Rectangle(0, r.Location.Y, r.Location.X, i.Size.Height - r.Location.Y)); //LEFT
            g.FillRectangle(sb, new Rectangle(r.Location.X, r.Location.Y + r.Size.Height + 1, i.Size.Width - r.Location.X, i.Size.Height - r.Location.Y - r.Size.Height - 1)); //BOTTOM
            g.FillRectangle(sb, new Rectangle(r.Location.X + r.Size.Width + 1, r.Location.Y, i.Size.Width - r.Location.X - r.Size.Width - 1, r.Size.Height + 1)); //RIGHT
            g.DrawRectangle(p, r);
            g.Dispose();
        }

        void l3_MouseUp(object sender, MouseEventArgs e)
        {
            _Previous = null;
        }

        void l3_MouseMove(object sender, MouseEventArgs e)
        {
            if (_Previous != null)
            {
                if (l2.Image == null)
                {
                    Bitmap bmp = new Bitmap(l2.Width, l2.Height);
                    using (Graphics g = Graphics.FromImage(bmp))
                    {
                        g.Clear(Color.White);
                    }
                    l2.Image = bmp;
                }
                using (Graphics g = Graphics.FromImage(l2.Image))
                {
                    g.DrawLine(Pens.Black, _Previous.Value, e.Location);
                }
                l2.Invalidate();
                _Previous = e.Location;
            }
        }

        void l3_MouseDown(object sender, MouseEventArgs e)
        {
            _Previous = e.Location;
            l3_MouseMove(sender, e);
        }
    }

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

        public LayerControl(Size s)
        {
            this.Width = s.Width;
            this.Height = s.Height;

            image = new Bitmap(s.Width, s.Height);

            graphics = Graphics.FromImage(image);

            SetStyle(ControlStyles.OptimizedDoubleBuffer |
                    ControlStyles.AllPaintingInWmPaint |
                    ControlStyles.UserPaint, true);
        }

        protected override void OnPaint(PaintEventArgs e)
        {
            var bitMap = new Bitmap(image);

            image = bitMap;

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

            float[][] mtxItems = {
            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(mtxItems);

            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);
        }

        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);
            }
        }

        public Image Image
        {
            get
            {
                return image;
            }
            set
            {
                image = value;
                this.Invalidate();
            }
        }
    }
}

Any ideas? I need to draw like with MS Paint brush.

1
Does the mouse events fire when the LayerControl's background is transparent? - Jeroen van Langen
MouseEvents are firing in all cases, but g.DrawLine isn't drawing a line on l2 if getting called from l3 MouseDown callback. - yahacoxumi
If you hide the LayerControl 3? Wil it be shown? I would guess that the g.Clear(Color.Transparent); won't work. - Jeroen van Langen
If change places of l2 and l3 (order: l, l3, l2) and add callbacks on l2 instead of l3, all will work. But i need that layer order: l, l2, l3, so i need to add callbacks on l3 and draw on l2. - yahacoxumi
But it looks like the transparent of L3 doesn't work. So it looks like you can't solve it this way. I would use 3 bitmaps and render them to one. So you're only using one LayerControl. See as the bitmaps are layers. Paint on one of the bitmaps. Merge them into a backpage that will be displayed in one LayerControl - Jeroen van Langen

1 Answers

0
votes

I just had to invalidate layer l3 after drawing on layer l2.