free-form crop selection doesn't work properly

后端 未结 1 1895
一个人的身影
一个人的身影 2020-12-12 04:40

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 po

1条回答
  •  小蘑菇
    小蘑菇 (楼主)
    2020-12-12 05:32

    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:

    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 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..

    0 讨论(0)
提交回复
热议问题