1

Before starting a project, I want to know beforehand whether the following would work.
The application creates a System.Drawing.Bitmap and paints on it.

The Bitmap is much larger than the PictureBox. The Height of the Bitmap and the PictureBox are the same. Now I would like to be able to move the Image from left to right within (along) the PictureBox by pressing the left mouse button and moving it.

See the drawing:

PictureBox shows part of a bigger image

Jimi
  • 29,621
  • 8
  • 43
  • 61
Daniel
  • 374
  • 1
  • 12
  • A PBox.Image is fixed. A common and simple solution nests the PBox in a Panel and moves the whole PBox in the Panel. – TaW Apr 22 '21 at 18:33
  • [Zoom and translate an Image from the mouse location](https://stackoverflow.com/a/61964222/7444103): follow the animation to *the end*, then check the code. BTW, you're missing some anti-alias there. – Jimi Apr 22 '21 at 18:56
  • Thanks a lot to you two. @Jimi Great idea to inherit from ‘PictureBox’ and develop something of your own. It works great! – Daniel Apr 22 '21 at 19:26
  • That's just to ease the mouse interaction. The *idea* behind that code is to only handle the Bitmap *descriptor*, aka the RectangleF that defines the bounds of a Bitmaps, considering the sum of the effects applied the last moment only. This way, you just need to handle the *shape* of a Image, not its content. -- The image in the animation is almost a 4K in size: using this method, you can deal with it as it was a much smaller object, so it gets pretty fast, even when you have a lot of effects/transformations applied. – Jimi Apr 22 '21 at 19:34
  • I have now read that out of the code. I commented out what I don't need (for example zooming); and I made ```new PointF(imageLocation.X + (e.Location.X - mouseLocation.X), imageLocation.Y);``` out of ```new PointF(imageLocation.X + (e.Location.X - mouseLocation.X), imageLocation.Y+ (e.Location.Y - mouseLocation.Y));``` because I don't want to move in height. – Daniel Apr 22 '21 at 19:45

1 Answers1

0

I just realized that I haven't answered yet, which I am trying to make up for. As a solution, I use Jimi's solution. I've shortened the code here to meet my needs.

using System;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.IO;
using System.Windows.Forms;

namespace Zoom_an_image_from_the_mouse_location
{
    public partial class FormMain : Form
    {
        public FormMain()
        {
            InitializeComponent();
            string imagePath = "C:\\Users\\yourPath\\Pictures\\....jpeg";
            drawingImage = (Bitmap)Image.FromStream(new MemoryStream(File.ReadAllBytes(imagePath)));
            imageRect = new RectangleF(Point.Empty, drawingImage.Size);

            canvas = new PictureBoxEx(new Size(525,700));
            canvas.Location = new Point(10, 10);
            canvas.MouseMove += this.canvas_MouseMove;
            canvas.MouseDown += this.canvas_MouseDown;
            canvas.MouseUp += this.canvas_MouseUp;
            canvas.Paint += this.canvas_Paint;
            this.Controls.Add(canvas);
        }

        private void FormMain_Load(object sender, EventArgs e)
        {
            this.BackColor = Color.FromArgb(174, 184, 177);
        }

        private void FormMain_FormClosing(object sender, FormClosingEventArgs e)
        {
        }

        private float rotationAngle = 0.0f;
        private float zoomFactor = 1.0f;

        private RectangleF imageRect = RectangleF.Empty;
        private PointF imageLocation = PointF.Empty;
        private PointF mouseLocation = PointF.Empty;

        private Bitmap drawingImage = null;
        private PictureBoxEx canvas = null;

        private void canvas_MouseDown(object sender, MouseEventArgs e)
        {
            if (e.Button != MouseButtons.Left) return;
            mouseLocation = e.Location;
            imageLocation = imageRect.Location;
            canvas.Cursor = Cursors.NoMove2D;
        }

        private void canvas_MouseMove(object sender, MouseEventArgs e)
        {
            if (e.Button != MouseButtons.Left) return;
            imageRect.Location =
                new PointF(imageLocation.X + (e.Location.X - mouseLocation.X),
                           imageLocation.Y); //+ (e.Location.Y - mouseLocation.Y));
            canvas.Invalidate();
        }

        private void canvas_MouseUp(object sender, MouseEventArgs e) =>
            canvas.Cursor = Cursors.Default;

        private void canvas_Paint(object sender, PaintEventArgs e)
        {
            var drawingRect = GetDrawingImageRect(imageRect);

            using (var mxRotation = new Matrix())
            using (var mxTransform = new Matrix())
            {

                e.Graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
                e.Graphics.PixelOffsetMode = PixelOffsetMode.Half;

                mxRotation.RotateAt(rotationAngle, GetDrawingImageCenterPoint(drawingRect));
                mxTransform.Multiply(mxRotation);

                e.Graphics.Transform = mxTransform;
                e.Graphics.DrawImage(drawingImage, drawingRect);
            }
        }


        #region Drawing Methods

        public RectangleF GetScaledRect(RectangleF rect, float scaleFactor) =>
            new RectangleF(rect.Location,
            new SizeF(rect.Width * scaleFactor, rect.Height * scaleFactor));

        public RectangleF GetDrawingImageRect(RectangleF rect) =>
            GetScaledRect(rect, zoomFactor);

        public PointF GetDrawingImageCenterPoint(RectangleF rect) =>
            new PointF(rect.X + rect.Width / 2f, rect.Y + rect.Height / 2f);

        #endregion
    }
}

[DesignerCategory("Code")]
public class PictureBoxEx : PictureBox
{
    public PictureBoxEx() : this(new Size(525, 700)) { }
    public PictureBoxEx(Size size)
    {
        SetStyle(ControlStyles.Selectable | ControlStyles.UserMouse, true);
        this.BorderStyle = BorderStyle.FixedSingle;
        this.Size = size;
    }
}
Daniel
  • 374
  • 1
  • 12