Asa_ImageZoom.cs 9.7 KB
using System;
using System.Windows.Forms;
using System.Drawing;
using System.Collections.Generic;

namespace Asa
{
    public class ImageZoom
    {
        public PointF offset = new PointF(0, 0);
        private List<PointF[]> polygon = new List<PointF[]>();
        private List<PointF> center = new List<PointF>();
        private List<string> text = new List<string>();

        private PictureBox pic;
        private Bitmap bmp;
        private Button btn_small;
        private Button btn_large;
        private Point oldPoint = new Point(0, 0);
        private PointF oldOffset = new PointF(0, 0);

        /// <summary>
        /// 判断鼠标按下,(用于避免bug,双击打开对话框的文件,会触发底下的picturebox的mousemove事件)
        /// </summary>
        private bool down = false;
        private float oldZoom = 0;
        private int zoomIdx = -1;
        private const int BUTTON_SIZE = 50;
        private readonly Color BUTTON_BACK = Color.FromArgb(128, 255, 255, 255);  //背景
        private readonly Color BUTTON_OVER = Color.FromArgb(128, 192, 255, 192);  //经过
        private readonly Color BUTTON_DOWN = Color.FromArgb(128, 255, 255, 192);  //按下
        private const float ZOOM_MAX = 2f;
        private const float ZOOM_MIN = 0.1f;
        private const float ZOOM_PRECISE = 0.05f;
        private readonly float[] ZOOM_SCALE = new float[] { 0.1f, 0.2f, 0.3f, 0.4f, 0.5f, 0.6f, 0.7f, 0.8f, 0.9f, 1.0f };

        public ImageZoom()
        {
            ZoomIdx = 1;
            ImageMove = true;
        }

        /// <summary>
        /// 用于显示的控件
        /// </summary>
        public PictureBox ShowControl
        {
            set
            {
                pic = value;
                pic.Paint += Pic_Paint;
                pic.Resize += Pic_Resize;
                pic.MouseWheel += Pic_MouseWheel;
                pic.MouseMove += Pic_MouseMove;
                pic.MouseUp += Pic_MouseUp;
                pic.MouseDown += Pic_MouseDown;

                btn_small = new Button();
                btn_small.BackColor = BUTTON_BACK;
                btn_small.Text = "-";
                btn_small.Font = new Font("宋体", 38f);
                btn_small.TextAlign = ContentAlignment.MiddleCenter;
                btn_small.Size = new Size(BUTTON_SIZE, BUTTON_SIZE);
                btn_small.Location = new Point(pic.ClientSize.Width - BUTTON_SIZE, pic.ClientSize.Height - BUTTON_SIZE);
                btn_small.Anchor = AnchorStyles.Right | AnchorStyles.Bottom;
                btn_small.FlatStyle = FlatStyle.Flat;
                btn_small.FlatAppearance.BorderSize = 0;
                btn_small.FlatAppearance.MouseOverBackColor = BUTTON_OVER;
                btn_small.FlatAppearance.MouseDownBackColor = BUTTON_DOWN;
                btn_small.Click += Btn_small_Click;
                pic.Controls.Add(btn_small);

                btn_large = new Button();
                btn_large.BackColor = BUTTON_BACK;
                btn_large.Text = "+";
                btn_large.Font = new Font("宋体", 38f);
                btn_large.TextAlign = ContentAlignment.MiddleCenter;
                btn_large.Size = new Size(BUTTON_SIZE, BUTTON_SIZE);
                btn_large.Location = new Point(pic.ClientSize.Width - BUTTON_SIZE - BUTTON_SIZE, pic.ClientSize.Height - BUTTON_SIZE);
                btn_large.Anchor = AnchorStyles.Right | AnchorStyles.Bottom;
                btn_large.FlatStyle = FlatStyle.Flat;
                btn_large.FlatAppearance.BorderSize = 0;
                btn_large.FlatAppearance.MouseOverBackColor = BUTTON_OVER;
                btn_large.FlatAppearance.MouseDownBackColor = BUTTON_DOWN;
                btn_large.Click += Btn_large_Click;
                pic.Controls.Add(btn_large);
            }
        }

        /// <summary>
        /// 图像移动
        /// </summary>
        public bool ImageMove { set; get; }

        /// <summary>
        /// 自动缩放比例
        /// </summary>
        public bool AutoZoom { set; get; }

        /// <summary>
        /// 缩放比例
        /// </summary>
        public float Zoom { private set; get; }

        public int ZoomIdx
        {
            set
            {
                if (value < 0)
                    zoomIdx = 0;
                else if (value > ZOOM_SCALE.Length - 1)
                    zoomIdx = ZOOM_SCALE.Length - 1;
                else
                    zoomIdx = value;
                Zoom = ZOOM_SCALE[ZoomIdx];
                oldZoom = Zoom;
            }
            get
            {
                return zoomIdx;
            }
        }

        public void Update()
        {
            if (bmp == null) return;
            if (AutoZoom)
            {
                float f1 = pic.Width / (float)bmp.Width;
                float f2 = pic.Height / (float)bmp.Height;
                Zoom = Math.Min(f1, f2);
            }
            pic.Refresh();
        }

        public void Update(Bitmap bmp)
        {
            //drawRect = new Rectangle();
            this.bmp = bmp;
            if (AutoZoom)
            {
                float f1 = pic.Width / (float)bmp.Width;
                float f2 = pic.Height / (float)bmp.Height;
                oldZoom = Zoom = Math.Min(f1, f2);
            }
            polygon.Clear();
            pic.Refresh();
        }

        public string[] ZoomName()
        {
            string[] rtn = new string[ZOOM_SCALE.Length];
            for (int i = 0; i < rtn.Length; i++)
                rtn[i] = Convert.ToInt32(ZOOM_SCALE[i] * 100) + "%";
            return rtn;
        }

        /// <summary>
        /// 添加轮廓
        /// </summary>
        /// <param name="pt"></param>
        /// <param name="center"></param>
        /// <param name="text"></param>
        public void AddOutline(PointF[] pt, PointF center, string text)
        {
            polygon.Add(pt);
            this.center.Add(center);
            this.text.Add(text);
        }

        public void ClearOutline()
        {
            polygon.Clear();
            center.Clear();
            text.Clear();
        }



        private void Btn_large_Click(object sender, EventArgs e)
        {
            oldZoom = Zoom;
            if (Zoom < ZOOM_MAX) Zoom += ZOOM_PRECISE;
            float w1 = (bmp.Width * Zoom - bmp.Width * oldZoom) / 2;
            offset.X -= w1;
            w1 = (bmp.Height * Zoom - bmp.Height * oldZoom) / 2;
            offset.Y -= w1;
            pic.Refresh();
        }

        private void Btn_small_Click(object sender, EventArgs e)
        {
            oldZoom = Zoom;
            if (Zoom > ZOOM_MIN) Zoom -= ZOOM_PRECISE;

            float w1 = (bmp.Width * Zoom - bmp.Width * oldZoom) / 2;
            offset.X -= w1;
            w1 = (bmp.Height * Zoom - bmp.Height * oldZoom) / 2;
            offset.Y -= w1; 
            pic.Refresh();
        }

        private void Pic_Paint(object sender, PaintEventArgs e)
        {
            if (bmp == null) return;

            RectangleF destRect = new RectangleF(offset.X, offset.Y, bmp.Width * Zoom, bmp.Height * Zoom);
            RectangleF srcRect = new RectangleF(0, 0, bmp.Width, bmp.Height);
            e.Graphics.DrawImage(bmp, destRect, srcRect, GraphicsUnit.Pixel);

            for (int i = 0; i < polygon.Count; i++)
            {
                float x = offset.X + center[i].X * Zoom;
                float y = offset.Y + center[i].Y * Zoom;
                PointF[] points = new PointF[polygon[i].Length];
                RectangleF re = new RectangleF(x - 20, y - 20, 40, 40);
                Font f = new Font("宋体", 12f, FontStyle.Bold);
                SizeF sizeF = e.Graphics.MeasureString(text[i], f);

                for (int j = 0; j < points.Length; j++)
                {
                    points[j].X = offset.X + polygon[i][j].X * Zoom;
                    points[j].Y = offset.Y + polygon[i][j].Y * Zoom;
                }
                e.Graphics.DrawPolygon(Pens.Red, points);
                if (text[i] == null) continue;
                SolidBrush brush = new SolidBrush(Color.FromArgb(150, 255, 255, 0));
                e.Graphics.FillEllipse(brush, re);
                e.Graphics.DrawString(text[i], f, Brushes.Red, x - sizeF.Width / 2, y - sizeF.Height / 2);
            }
        }

        private void Pic_Resize(object sender, EventArgs e)
        {
            if (AutoZoom) Update();
        }

        private void Pic_MouseWheel(object sender, MouseEventArgs e)
        {
            if (AutoZoom) return;

            oldZoom = Zoom;
            if (e.Delta > 0)
            {
                if (Zoom < ZOOM_MAX) Zoom += ZOOM_PRECISE;
            }
            else
            {
                if (Zoom > ZOOM_MIN) Zoom -= ZOOM_PRECISE;
            }

            float w1 = (e.X - offset.X) * (bmp.Width * Zoom) / (bmp.Width * oldZoom);
            offset.X = e.X - w1;
            w1 = (e.Y - offset.Y) * (bmp.Height * Zoom) / (bmp.Height * oldZoom);
            offset.Y = e.Y - w1;
            pic.Refresh();
        }

        private void Pic_MouseMove(object sender, MouseEventArgs e)
        {
            if (!down) return;
            if (ImageMove && e.Button == MouseButtons.Left)
            {
                offset.X = e.X - oldPoint.X + oldOffset.X;
                offset.Y = e.Y - oldPoint.Y + oldOffset.Y;
                pic.Refresh();
            }
        }

        private void Pic_MouseUp(object sender, MouseEventArgs e)
        {
            down = false;
        }

        private void Pic_MouseDown(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left || e.Button == MouseButtons.Right)
            {
                down = true;
                oldPoint = e.Location;
                oldOffset = offset;
            }
        }
    }
}