Wednesday, 20 July 2016

Drawing Canvas on Winforms

  public partial class ImagePanel : UserControl, IComponent
    {

        Point pt;  // the point in the image that will be viewable in the top left corner (0,0) of the viewable rectangle(panel)
        Pen pen = new Pen(Color.Black);     
        public Bitmap canvas;  // Editable drawing
        Graphics canvas_graphics;  
        public List<Point> points; // Points of currently drawing line
        protected Point scrollPosition;
        protected Point clickPosition;
        private int pan_horizontal;
        private int pan_vertical;
        int viewRectWidth, viewRectHeight; // view window width and height
        public bool zoom_scroll_change;
        public bool pen_change;
        public float zoom_coef = 0.02f;
        float zoom = 1.0f;
        Size canvasSize = new Size(60, 40);
        Bitmap background_image; // canvas background - this will not be edited
        InterpolationMode interMode = InterpolationMode.HighQualityBilinear;

        public float Zoom
        {
            get { return zoom; }
            set
            {
                if (value < 0.001f) value = 0.001f;
                RecordZoomScrollPosition();
                zoom = value;
                ChangePenSizeForZoom();
                displayScrollbar();
                setScrollbarValues();
                SetScrollZoomPosition();
                Invalidate();
            }
        }
      
        public Size CanvasSize
        {
            get { return canvasSize; }
            set
            {
                canvasSize = value;
                displayScrollbar();
                setScrollbarValues();
                Invalidate();
            }
        }

     
        public InterpolationMode InterpolationMode
        {
            get { return interMode; }
            set { interMode = value; }
        }


        public ImagePanel()   // Constructor
        {
            InitializeComponent();

            try
            {
                // Set the value of the double-buffering style bits to true.
                SetStyle(ControlStyles.AllPaintingInWmPaint |
                  ControlStyles.UserPaint | ControlStyles.ResizeRedraw |
                  ControlStyles.UserPaint | ControlStyles.DoubleBuffer, true);

                pt = new Point(0, 0);  // top left corner of visible rectangle of image
                points = new List<Point>(); // list of points to draw
                pen = new Pen(Color.Black);  // Setup Pen          
                pen.StartCap = LineCap.Round;
                pen.EndCap = LineCap.Round;
            }
            catch (Exception ex)
            {
                var methodName = new StackTrace(ex).GetFrame(0).GetMethod().Name;
                Errorlog.Errorlog.WriteToErrorLog(ex.Message, ex.StackTrace, "Error", methodName);
            }
        }
 

        public void SetBackgroundAndCanvasImages(Bitmap background_image_input, Bitmap canvas_image_input) // Set background and canvas image
        {
            SetBackgroundImage(background_image_input); // Set background first
            SetCanvasImage(canvas_image_input);   // Set canvas
            RefreshControlsAndDisplay();  // update controls and display
        }

        private void SetBackgroundImage(Bitmap image)  // Set background image
        {
            background_image = image;
        }

        private void SetCanvasImage(Bitmap image)  // Check if canvas exists, otherwise create blank canvas
        {
            canvas = image;
        }
       
        private void RefreshControlsAndDisplay()  // Refresh combined image and display
        {
            displayScrollbar();
            setScrollbarValues();
            Invalidate();
        }


        private void displayScrollbar()
        {
            try
            {
                viewRectWidth = Width;
                viewRectHeight = Height;
                if (background_image != null) canvasSize = background_image.Size;
                if (viewRectWidth > canvasSize.Width * zoom) // If the zoomed image is wider than view window, show the HScrollBar and adjust the view window
                {
                    hScrollBar1.Visible = false;
                    hScrollBar1.Value = 1;
                    viewRectHeight = Height;
                }
                else
                {
                    hScrollBar1.Visible = true;
                    viewRectHeight = Height - hScrollBar1.Height;
                }

                if (viewRectHeight > canvasSize.Height * zoom)   // If the zoomed image is taller than view window, show the VScrollBar and adjust the view window
                {

                    vScrollBar1.Visible = false;
                    vScrollBar1.Value = 1;
                    viewRectWidth = Width;
                }
                else
                {
                    vScrollBar1.Visible = true;
                    viewRectWidth = Width - vScrollBar1.Width;
                }

                // Set up scrollbars
                hScrollBar1.Location = new Point(0, Height - hScrollBar1.Height);
                hScrollBar1.Width = viewRectWidth;
                vScrollBar1.Location = new Point(Width - vScrollBar1.Width, 0);
                vScrollBar1.Height = viewRectHeight;
            }
            catch (Exception ex)
            {
                var methodName = new StackTrace(ex).GetFrame(0).GetMethod().Name;
                Errorlog.Errorlog.WriteToErrorLog(ex.Message, ex.StackTrace, "Error", methodName);
            }
        }

        private void setScrollbarValues()
        {
            try
            {
                // Set the Maximum, Minimum, LargeChange and SmallChange properties.
                vScrollBar1.Minimum = 0;
                hScrollBar1.Minimum = 0;

                // If the offset does not make the Maximum less than zero, set its value.
                if ((canvasSize.Width * zoom - viewRectWidth) > 0)
                {
                    hScrollBar1.Maximum = (int)(canvasSize.Width * zoom) - viewRectWidth;
                }
                // If the VScrollBar is visible, adjust the Maximum of the
                // HSCrollBar to account for the width of the VScrollBar. 
                if (vScrollBar1.Visible)
                {
                    hScrollBar1.Maximum += vScrollBar1.Width;
                }
                hScrollBar1.LargeChange = hScrollBar1.Maximum / 10;
                hScrollBar1.SmallChange = hScrollBar1.Maximum / 20;

                // Adjust the Maximum value to make the raw Maximum value
                // attainable by user interaction.
                hScrollBar1.Maximum += hScrollBar1.LargeChange;

                // If the offset does not make the Maximum less than zero, set its value.   
                if ((canvasSize.Height * zoom - viewRectHeight) > 0)
                {
                    vScrollBar1.Maximum = (int)(canvasSize.Height * zoom) - viewRectHeight;
                }

                // If the HScrollBar is visible, adjust the Maximum of the
                // VSCrollBar to account for the width of the HScrollBar.
                if (hScrollBar1.Visible)
                {
                    vScrollBar1.Maximum += hScrollBar1.Height;
                }
                vScrollBar1.LargeChange = vScrollBar1.Maximum / 10;
                vScrollBar1.SmallChange = vScrollBar1.Maximum / 20;

                // Adjust the Maximum value to make the raw Maximum value
                // attainable by user interaction.
                vScrollBar1.Maximum += vScrollBar1.LargeChange;
            }
            catch (Exception ex)
            {
                var methodName = new StackTrace(ex).GetFrame(0).GetMethod().Name;
                Errorlog.Errorlog.WriteToErrorLog(ex.Message, ex.StackTrace, "Error", methodName);
            }
        }

        public void SetMousePostion(Point position)  // Set mouse position
        {
            clickPosition = position;
        }


        public void Pan(Point position)  // Pan the image
        {
            try
            {
                pan_horizontal = scrollPosition.X + clickPosition.X - position.X;  // Mouse traveled X from click position
                pan_vertical = scrollPosition.Y + clickPosition.Y - position.Y; // Mouse traveled Y from click position          
                if (pan_horizontal < 0) pan_horizontal = 0;  // If we get a negative number then we've reached the begginning of the scroll
                if (pan_vertical < 0) pan_vertical = 0;
                if (pan_horizontal >= hScrollBar1.Maximum - hScrollBar1.LargeChange) pan_horizontal = hScrollBar1.Maximum - hScrollBar1.LargeChange - 1; // If we get a negative number then we've reached the begginning of the scroll
                if (pan_vertical >= vScrollBar1.Maximum - vScrollBar1.LargeChange) pan_vertical = vScrollBar1.Maximum - vScrollBar1.LargeChange - 1;
                if (hScrollBar1.Visible) hScrollBar1.Value = pan_horizontal;  // Set new scrollposition
                if (vScrollBar1.Visible) vScrollBar1.Value = pan_vertical;
                Invalidate();
            }
            catch (Exception ex)
            {
                var methodName = new StackTrace(ex).GetFrame(0).GetMethod().Name;
                Errorlog.Errorlog.WriteToErrorLog(ex.Message, ex.StackTrace, "Error", methodName);
            }
        }


        public void RecordScrollPostion() // Record previous scroll position
        {
            scrollPosition = new Point() { X = hScrollBar1.Value, Y = vScrollBar1.Value };
        }
       
        float zoom_position_previous; // Record previous zoom and scroll position
        Point scroll_maximum;
        public void RecordZoomScrollPosition()
        {
            try
            {
                RecordScrollPostion();
                zoom_position_previous = zoom;
                scroll_maximum = new Point(hScrollBar1.Maximum, vScrollBar1.Maximum);
            }
            catch (Exception ex)
            {
                var methodName = new StackTrace(ex).GetFrame(0).GetMethod().Name;
                Errorlog.Errorlog.WriteToErrorLog(ex.Message, ex.StackTrace, "Error", methodName);
            }

        }

        // SetScrollPostion
        float h_coef;
        float v_coef;
        public void SetScrollZoomPosition()
        {
            try
            {
                h_coef = (float)scrollPosition.X / (float)scroll_maximum.X;
                v_coef = (float)scrollPosition.Y / (float)scroll_maximum.Y;

                if (hScrollBar1.Visible == true)
                {
                    if ((int)(hScrollBar1.Maximum * h_coef) < hScrollBar1.Minimum) hScrollBar1.Value = hScrollBar1.Minimum;
                    else
                    {
                        hScrollBar1.Value = (int)(hScrollBar1.Maximum * h_coef);
                    }
                }
                if (vScrollBar1.Visible == true)
                {
                    if ((int)(vScrollBar1.Maximum * v_coef) < vScrollBar1.Minimum) vScrollBar1.Value = vScrollBar1.Minimum;
                    else vScrollBar1.Value = (int)(vScrollBar1.Maximum * v_coef);
                }
            }
            catch (Exception ex)
            {
                var methodName = new StackTrace(ex).GetFrame(0).GetMethod().Name;
                Errorlog.Errorlog.WriteToErrorLog(ex.Message, ex.StackTrace, "Error", methodName);
            }

        }


        // Refresh control if either the vertical or horizontal scroll changes
        private void vScrollBar1_Scroll(object sender, ScrollEventArgs e)
        {
            Invalidate();
        }

        // Add points to be drawn
        public void AddPoint(Point point)
        {
            points.Add(new Point() { X = (int)((float)point.X / zoom) + pt.X, Y = (int)((float)point.Y / zoom) + pt.Y });         
        }

        // Region/area of control to refresh - reduces lag
        List<Point> region = new List<Point>();
        public Region GetRegionByLine(Point point)
        {
            RectangleF rf = new RectangleF(point.X - 50, point.Y - 50, 100, 100);
            return new Region(rf);
        }

        // Keep the size of new pen marking the same regardless of zoom level
        public void ChangePenSizeForZoom()
        {
            pen.Width = (pen_size / zoom);
        }

        /// Change pen size
        float pen_size = 3;
        public void ChangePenSize(int size)
        {
            pen_size = size;
            ChangePenSizeForZoom();
        }

        // Change pen color
        public void ChangePenColor(Color color)
        {
            SolidBrush b = new SolidBrush(color);
            pen.Brush = b; // = color;
        }

        // Set minimum zoom.  Set this so the image doesn't shrink smaller then the veiwing rectangle
        public int SetMinimumZoom()
        {
        
                int width_zoom=0;
                int height_zoom=0;
                try
                {
                    width_zoom = (int)Math.Floor((float)Width / (float)canvasSize.Width / zoom_coef);
                    height_zoom = (int)Math.Floor((float)Height / (float)canvasSize.Height / zoom_coef);
                }
                catch (Exception ex)
                {
                    var methodName = new StackTrace(ex).GetFrame(0).GetMethod().Name;
                    Errorlog.Errorlog.WriteToErrorLog(ex.Message, ex.StackTrace, "Error", methodName);
                }

                if (width_zoom > height_zoom) return height_zoom;
                else return width_zoom;
           
        }

        // On Paint
        Rectangle srcRect, distRect;
        Matrix mx; // create an identity matrix
        Graphics g;
        protected override void OnPaint(PaintEventArgs e)
        {
            try
            {
                base.OnPaint(e);

                //draw image
                if (background_image != null)
                {
                    if (pen_change == false)
                    {
                        pt = new Point((int)(hScrollBar1.Value / zoom), (int)(vScrollBar1.Value / zoom));  // Get the point in the image that will be viewable in the top left corner of the viewable rectangle(panel)

                        srcRect = new Rectangle(pt, new Size((int)(viewRectWidth / zoom), (int)(viewRectHeight / zoom))); // view a portion of image

                        distRect = new Rectangle((int)(-srcRect.Width / 2), -srcRect.Height / 2, srcRect.Width, srcRect.Height); // the center of apparent image is on origin

                        mx = new Matrix(); // create an identity matrix
                        mx.Scale(zoom, zoom); // zoom image
                        mx.Translate(viewRectWidth / 2.0f, viewRectHeight / 2.0f, MatrixOrder.Append); // move image to view window center

                    }
                    g = e.Graphics; // Get graphics from control

                    g.InterpolationMode = interMode;
                    g.Transform = mx;
                    g.DrawImage(background_image, distRect, srcRect, GraphicsUnit.Pixel);
                    //canvas_graphics.DrawEllipse(pen, pen_location.X, pen_location.Y, 10, 10); // Hovering pen)
                    if (points.Count > 0)
                    {
                        canvas_graphics = Graphics.FromImage(canvas);
                        canvas_graphics.CompositingMode = CompositingMode.SourceCopy;
                        //canvas_graphics.SmoothingMode = SmoothingMode.HighSpeed;
                        canvas_graphics.DrawLines(pen, points.ToArray());
                        g.DrawImage(canvas, distRect, srcRect, GraphicsUnit.Pixel);
                        //canvas_graphics.Dispose();
                    }
                    else g.DrawImage(canvas, distRect, srcRect, GraphicsUnit.Pixel);
                    //g.Dispose();
                    pen_change = false;
                }
            }
            catch (Exception ex)
            {
                var methodName = new StackTrace(ex).GetFrame(0).GetMethod().Name;
                Errorlog.Errorlog.WriteToErrorLog(ex.Message, ex.StackTrace, "Error", methodName);
            }
        }

        // Save new lines to bitmap
        public void SaveToBitmap()
        {
            try
            {
                if (points.Count == 0)
                    return;

                using (Graphics g = Graphics.FromImage(canvas))
                {
                    if (points.Count == 1)
                    {
                        //g.DrawLine(pen, points[0], points[0]); // Just draw current line on bitmap}
                    }
                    else
                    {
                        g.DrawLines(pen, points.ToArray()); // Just draw current line on bitmap}
                    }
                }
            }
            catch (Exception ex)
            {
                var methodName = new StackTrace(ex).GetFrame(0).GetMethod().Name;
                Errorlog.Errorlog.WriteToErrorLog(ex.Message, ex.StackTrace, "Error", methodName);
            }
        }

        protected override void OnLoad(EventArgs e)
        {
            try
            {
                displayScrollbar();
                setScrollbarValues();
                base.OnLoad(e);
            }
            catch (Exception ex)
            {
                var methodName = new StackTrace(ex).GetFrame(0).GetMethod().Name;
                Errorlog.Errorlog.WriteToErrorLog(ex.Message, ex.StackTrace, "Error", methodName);
            }
        }

        protected override void OnResize(EventArgs e)
        {
            try
            {
                displayScrollbar();
                setScrollbarValues();
                base.OnResize(e);
            }
            catch (Exception ex)
            {
                var methodName = new StackTrace(ex).GetFrame(0).GetMethod().Name;
                Errorlog.Errorlog.WriteToErrorLog(ex.Message, ex.StackTrace, "Error", methodName);
            }
        }

    }

No comments:

Post a Comment