1

I made a program that lets you do a random selection then the selected area to save into a new image, but I got a problem it doesn't work how it's supposed to... I will post my code here so you can have a look:

private List<Point> Points = null;
private bool Selecting = false;
private Bitmap SelectedArea = null;

private void pictureBox5_MouseDown(object sender, MouseEventArgs e)
{
  Points = new List<Point>();
  Selecting = true;
}

private void pictureBox5_MouseMove(object sender, MouseEventArgs e)
{
  if (!Selecting) return;
  Points.Add(new Point(e.X, e.Y));
  pictureBox5.Invalidate();
}

private void pictureBox5_MouseUp(object sender, MouseEventArgs e)
{
  Selecting = false;

  // Copy the selected area.
  SelectedArea = GetSelectedArea(pictureBox5.Image, Color.Transparent, Points);

  SelectedArea.Save(@"C:\Users\User\Desktop\Gallery\image" + NumberOfClick.ToString() + "cropped.jpeg", ImageFormat.Jpeg);

  string filename = @"C:\Users\User\Desktop\Gallery\image" + NumberOfClick.ToString() + "cropped.jpeg";

  if(File.Exists(filename))
  {
    button1.Visible = true;
    pictureBox5.Visible = false;
  }
}

private void pictureBox5_Paint(object sender, PaintEventArgs e)
{
  if ((Points != null) && (Points.Count > 1))
  {
    using (Pen dashed_pen = new Pen(Color.Black))
    {
      dashed_pen.DashPattern = new float[] { 5, 5 };
      e.Graphics.DrawLines(Pens.White, Points.ToArray());
      e.Graphics.DrawLines(dashed_pen, Points.ToArray());
    }
  }
}

private Bitmap GetSelectedArea(Image source, Color bg_color, List<Point> points)
{
  // Make a new bitmap that has the background
  // color except in the selected area.
  Bitmap big_bm = new Bitmap(source);
  using (Graphics gr = Graphics.FromImage(big_bm))
  {
    // Set the background color.
    gr.Clear(bg_color);

    // Make a brush out of the original image.
    using (Brush br = new TextureBrush(source))
    {
      // Fill the selected area with the brush.
      gr.FillPolygon(br, points.ToArray());

      // Find the bounds of the selected area.
      Rectangle source_rect = GetPointListBounds(points);

      // Make a bitmap that only holds the selected area.
      Bitmap result = new Bitmap(
        source_rect.Width, source_rect.Height);

      // Copy the selected area to the result bitmap.
      using (Graphics result_gr = Graphics.FromImage(result))
      {
        Rectangle dest_rect = new Rectangle(0, 0,
                                            source_rect.Width, source_rect.Height);
        result_gr.DrawImage(big_bm, dest_rect,
                            source_rect, GraphicsUnit.Pixel);
      }

      // Return the result.
      return result;
    }
  }
}

private Rectangle GetPointListBounds(List<Point> points)
{
  int xmin = points[0].X;
  int xmax = xmin;
  int ymin = points[0].Y;
  int ymax = ymin;

  for (int i = 1; i < points.Count; i++)
  {
    if (xmin > points[i].X) xmin = points[i].X;
    if (xmax < points[i].X) xmax = points[i].X;
    if (ymin > points[i].Y) ymin = points[i].Y;
    if (ymax < points[i].Y) ymax = points[i].Y;
  }

  return new Rectangle(xmin, ymin, xmax - xmin, ymax - ymin);
}

This is how I am doing and saving the cropped images.

And also this is how I am uploading the pictures:

OpenFileDialog f = new OpenFileDialog();
f.Filter = "Image files (*.jpg, *.jpeg, *.jpe, *.jfif, *.png) | *.jpg; *.jpeg; *.jpe; *.jfif; *.png";

if (f.ShowDialog() == DialogResult.OK)
{
  currentImage = Image.FromFile(f.FileName);
  pictureBox1.Image = currentImage;
}

pictureBox1.Image.Save(@"C:\Users\User\Desktop\Gallery\image1.jpeg", ImageFormat.Jpeg);

DialogResult result = MessageBox.Show("Crop your image", "Information", MessageBoxButtons.OK);

if(result == DialogResult.OK)
{
  pictureBox5.Visible = true;
  button1.Visible = false;
  pictureBox5.Image = pictureBox1.Image;
}

In pictureBox5 I am selecting and cropping the picture.

mySelection croppedImage

C. Cristi
  • 569
  • 1
  • 7
  • 21
  • You need to either set the SizeMode to Normal instead of Zoom or need to zoom the selected points as well. – TaW Nov 20 '16 at 16:05
  • 1
    Yeah, it worked but I need to get my image stretched into the picturebox too.. how do I zoom the selected points? – C. Cristi Nov 20 '16 at 16:25

1 Answers1

3

You need to calculate the zoom and the offset of the image when it is zoomed.

Here is how to do that; this assumes the PictureBox is indeed in Zoom mode, not in Stretch mode. If you stretch it you need to calculate the zooms for x and y separately..

SizeF sp = pictureBox5.ClientSize;
SizeF si = pictureBox5.Image.Size;    
float rp = sp.Width / sp.Height;   // calculate the ratios of
float ri = si.Width / si.Height;   // pbox and image   

float zoom = (rp > ri) ? sp.Height / si.Height : sp.Width / si.Width;

float offx = (rp > ri) ? (sp.Width - si.Width * zoom) / 2 : 0;
float offy = (rp <= ri)? (sp.Height - si.Height * zoom) / 2 : 0;
Point offset = Point.Round(new PointF(offx, offy));

You calculate this after setting the Image and after resizing the PictureBox..

Now you can transform each drawn point into a zoomed or an unzoomed coordinate:

    PointF zoomed(Point p1, float zoom, Point offset)
    {
        return (new PointF(p1.X * zoom + offset.X, p1.Y * zoom + offset.Y));
    }

    PointF unZoomed(Point p1, float zoom, Point offset)
    {
        return (new PointF((p1.X - offset.X) / zoom, (p1.Y - offset.Y) / zoom));
    }

Here is a demo the draws on to either a normal (left) or a zoomed in (middle) image. To the right is the result of placing your GetSelectedArea bitmap onto a PictureBox with a checkerbox background:

enter image description here

Case 1: If you store the points as they come in: In your GetSelectedArea method use this point list instead:

    private Bitmap GetSelectedArea(Image source, Color bg_color, List<Point> points)
    {
        var unzoomedPoints = 
            points.Select(x => Point.Round((unZoomed(Point.Round(x), zoom, offset))))
                  .ToList();
        // Make a new bitmap that has the background

After this replace each reference to points in the method by one to unzoomedPoints. Actually there are just two of them..

Case 2: If you store the points already 'unZoomed' :

Points.Add(unZoomed(e.Location, zoom, offset));

you can use the list directly..

TaW
  • 53,122
  • 8
  • 69
  • 111
  • TaW, do you have any ideas on this problem? http://stackoverflow.com/questions/40784541/issue-with-cropping-on-webcam – C. Cristi Nov 24 '16 at 19:55
  • Well you need to do a Points.Clear when loading a new image, I'd say. I noticed it while testing.. – TaW Nov 24 '16 at 20:11
  • and the part about croping without capturing with camera? – C. Cristi Nov 24 '16 at 20:15
  • i mean i want to make it so you can't crop while the videostream is still up so that you have to capture an image first.. – C. Cristi Nov 26 '16 at 08:29
  • I really can't help you there as I know nothing about the video capturing part. You may want to test the file system for the images but maybe this is not the way.. – TaW Nov 26 '16 at 08:39
  • I don't know how to send messages and I want to ask you something... I have a form size: 500,500 and I want to make it scrollable but without the scrollbar. Is this possible? – C. Cristi Dec 02 '16 at 12:02
  • Not t really afaik. How would the user do the scrolling? What you can do is add a the content to a Panel I and the Panel I to another Panel O. The base Panel O is dock=Fill and both are AutoScroll=false; Then you could act upone keys and move the outer panel O around inside Panel I.. – TaW Dec 02 '16 at 12:07
  • I want the user to scroll by dragging with mouse the content i want to be scrolled are some buttons – C. Cristi Dec 02 '16 at 14:39
  • Actually I want to make it scrollable with mouse wheel but without the scrollbar to be visbile (only vertical) – C. Cristi Dec 02 '16 at 19:19
  • Well as I suggested the way to go is to put the content into a large Panel and then move that Panel with the mouse. Many [examples](http://stackoverflow.com/questions/16384903/moving-a-control-by-dragging-it-with-the-mouse-in-c-sharp) around for this.. Here is a demo with a simple form: – TaW Dec 02 '16 at 19:44
  • `private void button24_Click(object sender, EventArgs e) { Form f2 = new Form(); f2.Size = new Size(400, 300); f2.AutoScroll = false; Panel pan = new Panel(); pan.Size = new Size(600, 100); pan.AutoScroll = false; for (int i = 1; i <= 10; i++) { Button b = new Button(); b.Text = "B" + (i); b.Name = "button_" + (i); b.Left = (b.Width + 12) * (i-1) ; b.Parent = pan; }` – TaW Dec 02 '16 at 19:46
  • `pan.Parent = f2; Point pPt = Point.Empty; pan.MouseDown += (ss, ee) => { pPt = ee.Location; }; pan.MouseMove += (ss, ee) => { if (ee.Button.HasFlag(MouseButtons.Left)) { Panel pa = ss as Panel; pa.Left = pa.Left + ee.X - pPt.X; } }; f2.Show();` – TaW Dec 02 '16 at 19:46
  • why you make the panel a little bit bigger? – C. Cristi Dec 02 '16 at 19:58
  • I don't understand why I need this new button? also I already added 2 panels ( panel1 which includes panel2 which includes like 6 buttons which i want to scroll down) – C. Cristi Dec 02 '16 at 20:16
  • You don't need it, it is just an example to study! The Panel must be bigger or else scrolling makes no sense! – TaW Dec 02 '16 at 20:40
  • 2
    That example scrolls into the panel or it actually scrolls the "button name" – C. Cristi Dec 02 '16 at 20:51
  • 2
    And does this work for mouse wheel or dragging with mouse? – C. Cristi Dec 02 '16 at 20:56
  • 'Why don't you try? – TaW Dec 02 '16 at 21:04
  • 2
    I will try in 5 min wait.. I had to do something.. it's a surprise :D ? – C. Cristi Dec 02 '16 at 21:11
  • 2
    I implemented your code it appears a new form with some buttons but when i click on it (not on the buttons) the buttons dissapear and when I try to scroll with mouse wheel nothing happens. – C. Cristi Dec 02 '16 at 21:37
  • If you read the code you can see that it only supports mousemove. as I wrote: it is an example to study.. It should not dispappear, though! – TaW Dec 02 '16 at 22:16
  • Strange. It certainly doesn't do that here. Did you add any code? – TaW Dec 02 '16 at 22:20
  • 2
    Actually I saw how this is supposed to work.. but it worked just a little amount of time because it dissapeared.. – C. Cristi Dec 02 '16 at 22:20
  • umm.. no I didn't just tried to make it look more "beautiful" – C. Cristi Dec 02 '16 at 22:21
  • 2
    So it doesn't disspears at you? but how does it looks like at you? you can control the scroll like left right? or it just goes right 1 time and then that's it? – C. Cristi Dec 02 '16 at 22:25
  • 2
    I think I figured it out somehow but it just goes too fast..? – C. Cristi Dec 02 '16 at 22:33
  • 2
    but mousedown isn't a click? – C. Cristi Dec 02 '16 at 22:41
  • 2
    No, mousedown if just the start of a full click. when I drag the panel it follows the mouse. I didn't code the mousewheel event. If you can't get it to work after your beautification try to revert it.. This is getting a little out of hand for comments though. – TaW Dec 02 '16 at 22:45
  • 2
    I would make another question but I can't ask right now actually wait: ok , try to answer here http://stackoverflow.com/questions/40682608/scroll-by-dragging-with-mouse – C. Cristi Dec 02 '16 at 22:51
  • Gee, looks like you want to scroll vertically now??? My code, if you look at it (!) only scolls horizontally.. – TaW Dec 02 '16 at 23:59
  • 2
    I know but I did for research the vertical one starting from your code but it the same bug.. the buttons either go too fast or dissapear – C. Cristi Dec 03 '16 at 07:53