Click here to Skip to main content
16,017,351 members
Please Sign up or sign in to vote.
4.00/5 (1 vote)
See more:
Hi,

I need to draw lines on the image which can be dragable, ie. by clicking on any line, I should be able to move that particular line along the image and finally save the image with lines.

I am using windows Form and picture box.

Please help
Posted
Updated 9-May-11 22:34pm
v2
Comments
Dalek Dave 10-May-11 4:34am    
Edited for Grammar and Readability.

That is not a simple question, it has two parts:
Drawing on an Image, and saving it: Easy, just get a Graphics object for the image, draw your lines, and save the file:
using (Graphics g = Graphics.FromImage(myImage))
    {
    g.DrawLine(pen, new Point(0, 0), new Point(myImage.Width, myImage.Height));
    }
myImage.Save(@"F:\temp\myimage.jpg", ImageFormat.Jpeg);

The second part is more complex:
How do you draw moveable lines?
You will have to handle the PictureBox Paint event, and remember where your lines are.
You will have to handle the PictureBox mouse events, and detect if you are on an existing line, or a new line - it is probably easier to pick them up at the ends only, rather than trying to work out if you are on a line by picking it up in the middle.

I'm not going to try and give you instructions for that here: it is far to much for a quick answer.

Google for basic drawing on WinForms, and follow any tutorial or other instructions you can find.
 
Share this answer
 
Comments
Olivier Levrey 10-May-11 3:47am    
Have my 5 for this answer. I gave a solution for the second part.
Dalek Dave 10-May-11 4:34am    
Good Answer.
OriginalGriff answered the first part. I will give the idea for the second one.

I supposed the lines are vertical lines, and the x potisions for each line are stored in an xLines array.
Add also a member int selectedLineIndex; in your form to store the current line index.

In your form constructor, add the following handlers for your PictureBox:
C#
//paint handler
pictureBox1.Paint += (sender, e) =>
{
    foreach (int x in xLines)
    {
        //draw the line
        e.Graphics.DrawLine(Pens.Red, x, 0, x, pictureBox1.Height);
    }
};
//mouse down handler
//this function will update selectedLineIndex
pictureBox1.MouseDown += (sender, e) =>
{
    //find the closest line from the current mouse position
    int minDistance = int.MaxValue;
    selectedLineIndex = 0;
    for (int k = 0; k < xLines.Length; k++)
    {
        int dist = Math.Abs(e.X - xLines[k]);
        if (dist < minDistance)
        {
            minDistance = dist;
            selectedLineIndex = k;
        }
    }
};
//mouse move handler
pictureBox1.MouseMove += (sender, e) =>
{
    //if the left button is not clicked, exit
    if ((MouseButtons & MouseButtons.Left) != MouseButtons.Left)
        return;
    //update the selected line position
    xLines[selectedLineIndex] = e.X;
    //redraw the picture box
    pictureBox1.Invalidate();
};


------------------------------------------------

To handle both horizontal and vertical lines:

C#
public partial class Form1 : Form
{
   int[] xLines;
   int[] yLines;
   int selectedLineIndex;
   //true to move vertical lines, false to move horizontal lines
   bool xline = false;

   public Form1()
   {
       InitializeComponent();

       int xmid = pictureBox1.Width / 2;
       int ymid = pictureBox1.Height / 2;
       xLines = new int[] { xmid, xmid / 2 };
       yLines = new int[] { ymid, ymid / 2 };
   }

   private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
   {
       //find the closest vertical line from the current mouse position
       int xminDistance = int.MaxValue;
       int xSelectedLineIndex = 0;
       for (int i = 0; i < xLines.Length; i++)
       {
           int dist = Math.Abs(e.X - xLines[i]);
           if (dist < xminDistance)
           {
               xminDistance = dist;
               xSelectedLineIndex = i;
           }
       }
       //find the closest horizontal line from the current mouse position
       int yminDistance = int.MaxValue;
       int ySelectedLineIndex = 0;
       for (int i = 0; i < yLines.Length; i++)
       {
           int dist = Math.Abs(e.Y - yLines[i]);
           if (dist < yminDistance)
           {
               yminDistance = dist;
               ySelectedLineIndex = i;
           }
       }
       //keep the closest line
       if (xminDistance < yminDistance)
       {
           selectedLineIndex = xSelectedLineIndex;
           xline = true;
       }
       else
       {
           selectedLineIndex = ySelectedLineIndex;
           xline = false;
       }
   }
   private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
   {
       //if the left button is not clicked, exit
       if ((MouseButtons & MouseButtons.Left) != MouseButtons.Left)
           return;
       //update the selected line position
       if (xline)
           xLines[selectedLineIndex] = e.X;
       else
           yLines[selectedLineIndex] = e.Y;
       //redraw the picture box
       pictureBox1.Invalidate();
   }
}
 
Share this answer
 
v5
Comments
Deepurs 10-May-11 4:09am    
Am getting error at this line --> int dist = Math.Abs(e.X - xLines[k].X);

Error 1 'int' does not contain a definition for 'X' and no extension method 'X' accepting a first argument of type 'int' could be found (are you missing a using directive or an assembly reference?)
Olivier Levrey 10-May-11 4:15am    
Sorry remove ".X".
In this code the closest line will be chosen automatically. If you want to choose it manually, you will need to add more code.
Do you want to ask the user to choose it with a combo box for example or something?
Deepurs 10-May-11 4:19am    
Yes. I need manual selection of lines. User should be able to select lines just by a mouse click on that particular line. Please help. And thank you so much
Deepurs 10-May-11 4:20am    
To be more specific user should be able to drag lines on the image and save.
Olivier Levrey 10-May-11 4:31am    
I updated my answer. You need to add a selectedLineIndex member, the MouseDown handler and change the MouseMove handler.
There are various ways to achieve this, I would go for a solution where you store a list of Line objects and render them after the base render pass of the PictureBox.
This would make it easy to move and change the style of all lines.

To save a image is fairly simple, there's a Save method on Image.

You could try extending PictureBox like this, this is a working example;



C#
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
namespace LinesTest
{
    public class LinedPictureBox : PictureBox
    {
        private IList<Line> lines = new List<Line>();
        private Line currentLine = null;
        private bool holdsA = false;
        public LinedPictureBox()
        {
            DoubleBuffered = true;
            MouseDown += HandleMouseDown;
            MouseMove += HandleMouseMove;
            MouseUp += (s, e) => currentLine = null;
        }
        private static int GetDistance(Point a, Point b)
        {
            int dx = a.X - b.X;
            int dy = a.Y - b.Y;
            return (int)Math.Sqrt(dx * dx + dy * dy);
        }
        private void HandleMouseMove(object sender, MouseEventArgs e)
        {
            if (currentLine != null)
            {
                if (holdsA)
                    currentLine.A = e.Location;
                else
                    currentLine.B = e.Location;
                Invalidate();
            }
        }
        private void HandleMouseDown(object sender, MouseEventArgs e)
        {
            Line aLine = (from line in lines orderby GetDistance(line.A, e.Location) select line).FirstOrDefault();
            Line bLine = (from line in lines orderby GetDistance(line.B, e.Location) select line).FirstOrDefault();
            if (aLine != null && bLine != null)
            {
                int aDistance = GetDistance(aLine.A, e.Location);
                int bDistance = GetDistance(bLine.B, e.Location);
                if (Math.Min(aDistance, bDistance) < 8)
                {
                    if (aDistance < bDistance)
                    {
                        currentLine = aLine;
                        holdsA = true;
                    }
                    else
                    {
                        currentLine = bLine;
                        holdsA = false;
                    }
                    return;
                }
            }
            currentLine = new Line { A = e.Location, B = e.Location, Pen = Pens.Red };
            holdsA = false;
            lines.Add(currentLine);
            Invalidate();
        }
        private void PaintLines(Graphics graphics)
        {
            foreach (Line line in lines)
                graphics.DrawLine(line.Pen, line.A, line.B);
        }
        protected override void OnPaint(PaintEventArgs e)
        {
            base.OnPaint(e);
            PaintLines(e.Graphics);
        }
        public void Save(string filename)
        {
            Image image = new Bitmap(Width, Height);
            Graphics graphics = Graphics.FromImage(image);
            switch (SizeMode)
            {
                case PictureBoxSizeMode.AutoSize:
                case PictureBoxSizeMode.Normal:
                    graphics.DrawImage(Image, new Point());
                    break;
                case PictureBoxSizeMode.StretchImage:
                    graphics.DrawImage(Image, new Rectangle(0, 0, Width, Height), new Rectangle(0, 0, Image.Width, Image.Height), GraphicsUnit.Pixel);
                    break;
                case PictureBoxSizeMode.CenterImage:
                    {
                        int x = Math.Max(0, (Image.Width - Width) / 2);
                        int y = Math.Max(0, (Image.Height - Height) / 2);
                        graphics.DrawImage(Image, new Rectangle(0, 0, Width, Height), new Rectangle(x, y, Width, Height), GraphicsUnit.Pixel);
                    }
                    break;
            }
            PaintLines(graphics);
            image.Save(filename);
        }
    }
    public class Line
    {
        public Point A { get; set; }
        public Point B { get; set; }
        public Pen Pen { get; set; }
    }
}


Hope this helps,
Fredrik
 
Share this answer
 
Comments
Dalek Dave 10-May-11 4:35am    
You worked hard on that!
Fredrik Bornander 10-May-11 4:55am    
Don't tell anyone, I'm supposed to be working.
Deepurs 10-May-11 5:03am    
How to use the extended pictureBox in my code? Sorry am new to C#
Fredrik Bornander 10-May-11 5:20am    
Just added the class to your solution and rebuild it.
The LinedPictureBox should show up in the ToolBox so you can just drag and drop it onto your form.
Manfred Rudolf Bihy 10-May-11 8:17am    
Great effort! 5+

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900