using System;
|
using System.Collections.Generic;
|
using System.Drawing.Drawing2D;
|
using System.Drawing;
|
using System.Linq;
|
using System.Text;
|
using System.Threading.Tasks;
|
using System.Diagnostics;
|
using static System.Net.Mime.MediaTypeNames;
|
|
namespace LB_VisionControl
|
{
|
public class UserPictureBox : PictureBox, IDisposable
|
{
|
public UserPictureBox(Control parent)
|
{
|
Point location = Point.Empty;
|
Size size = parent.ClientSize;
|
_zoomMatrix = new Matrix();
|
_rect = new Rectangle(0, 0, size.Width, size.Height);
|
this.Location = location;
|
this.Size = size;
|
this.SizeMode = PictureBoxSizeMode.Zoom;
|
this.parent = parent;
|
RegisterEvent();
|
}
|
|
#region 变量
|
Control parent { get; set; }
|
|
private Bitmap _currentImage = null;
|
private readonly object _syncLock = new object();
|
|
public Bitmap Image
|
{
|
get => _currentImage;
|
set
|
{
|
//// 根据首先设置的图像大小来计算缩放比例
|
//try
|
//{
|
// if (_currentImage == null)
|
// {
|
// _imgWidth = value.Width;
|
// _imgHeight = value.Height;
|
|
// // 计算自适应缩放比例
|
// float zoomX = (float)parent.ClientSize.Width / _imgWidth;
|
// float zoomY = (float)parent.ClientSize.Height / _imgHeight;
|
// _zoom = Math.Min(zoomX, zoomY); // 取较小的比例保证完全显示
|
// }
|
//}
|
//catch { }
|
|
lock (_syncLock)
|
{
|
try
|
{
|
// 释放现有资源
|
DisposeCurrentImage();
|
|
if (value != null)
|
{
|
// 创建新图像副本
|
//_currentImage = new Bitmap(value);
|
SetBackImage(value);
|
}
|
Refresh();
|
}
|
catch (Exception ex)
|
{
|
// 记录错误或处理异常
|
Debug.WriteLine($"【{DateTime.Now:HH:mm:ss.fff}】图像设置失败: {ex.Message}");
|
DisposeCurrentImage();
|
}
|
}
|
}
|
}
|
|
private void DisposeCurrentImage()
|
{
|
try
|
{
|
if (_tBrush != null)
|
{
|
_tBrush.Dispose();
|
_tBrush = null;
|
}
|
|
if (_currentImage != null)
|
{
|
_currentImage.Dispose();
|
_currentImage = null;
|
}
|
}
|
catch { }
|
}
|
|
/// <summary>
|
/// 用于内部激活是否重绘
|
/// </summary>
|
private bool _mEnable = true;
|
|
/// <summary>
|
/// 背景纹理画刷(设置图像后会将图像转换成纹理画刷,因为填充画刷的速度要比绘制图像的速度快得多)
|
/// </summary>
|
private TextureBrush _tBrush;
|
|
/// <summary>
|
/// 控件的矩形区域
|
/// </summary>
|
private Rectangle _rect = new Rectangle();
|
|
/// <summary>
|
/// 图像宽度
|
/// </summary>
|
private int _imgWidth = 1;
|
|
/// <summary>
|
/// 图像高度
|
/// </summary>
|
private int _imgHeight = 1;
|
|
/// <summary>
|
/// 按下平移键,鼠标在控件上的横坐标
|
/// </summary>
|
private float _mouseDownX = 0.0f;
|
|
/// <summary>
|
/// 按下平移键,鼠标在控件上的纵坐标
|
/// </summary>
|
private float _mouseDownY = 0.0f;
|
|
/// <summary>
|
/// 缩放系数
|
/// </summary>
|
private float _zoom = 1.0f;
|
|
/// <summary>
|
/// 图片左上角X轴的偏移量
|
/// </summary>
|
private float _imgX = 0.0f;
|
/// <summary>
|
/// 图片左上角Y轴的偏移量
|
/// </summary>
|
private float _imgY = 0.0f;
|
|
/// <summary>
|
/// 按下平移键,记录当前的_imgX
|
/// </summary>
|
private float _imgStartX = 0.0f;
|
|
/// <summary>
|
/// 按下平移键,记录当前的_imgY
|
/// </summary>
|
private float _imgStartY = 0.0f;
|
|
/// <summary>
|
/// 当前的缩放矩阵
|
/// </summary>
|
private Matrix _zoomMatrix = new Matrix();
|
|
/// <summary>
|
/// 最小缩放倍率
|
/// </summary>
|
private float _minZoom = 0.05f;
|
|
/// <summary>
|
/// 最大缩放倍率
|
/// </summary>
|
private float _maxZoom = 50.0f;
|
|
/// <summary>
|
/// 每次鼠标滚轮时,缩放系数的增量值
|
/// </summary>
|
private float _mouseZoomDV = 0.05f;
|
|
/// <summary>
|
/// 平移按键
|
/// </summary>
|
private MouseButtons _translateBtn = MouseButtons.Left;
|
|
/// <summary>
|
/// 指示是否正在执行平移操作
|
/// </summary>
|
private bool _inTranslate = false;
|
#endregion
|
|
#region 属性
|
/// <summary>
|
/// 获取是否正在执行平移操作
|
/// </summary>
|
public bool InTranslate
|
{
|
get { return _inTranslate; }
|
protected set
|
{
|
if (value != _inTranslate)
|
{
|
_inTranslate = value;
|
if (value)
|
{
|
OnStartTranslate();
|
}
|
else
|
{
|
OnStopTranslate();
|
}
|
}
|
}
|
}
|
#endregion
|
|
#region 方法
|
/// <summary>
|
/// 注册事件
|
/// </summary>
|
public void RegisterEvent()
|
{
|
//this.MouseDoubleClick += new MouseEventHandler(_ctrl_MouseDoubleClick);
|
this.MouseDown += new MouseEventHandler(_ctrl_MouseDown);
|
this.MouseMove += new MouseEventHandler(_ctrl_MouseMove);
|
this.MouseUp += new MouseEventHandler(_ctrl_MouseUp);
|
this.MouseEnter += new EventHandler(_ctrl_MouseEnter);
|
this.MouseWheel += new MouseEventHandler(_ctrl_MouseWheel);
|
this.Paint += new PaintEventHandler(_ctrl_Paint);
|
|
this.MouseDoubleClick += new MouseEventHandler(_ctrl_MouseDoubleDown);
|
}
|
|
/// <summary>
|
/// 释放背景纹理画刷
|
/// </summary>
|
protected virtual void tBrushDispose()
|
{
|
if (_tBrush != null)
|
{
|
_tBrush.Dispose();
|
_tBrush = null;
|
}
|
}
|
|
/// <summary>
|
/// 释放资源
|
/// </summary>
|
public new void Dispose()
|
{
|
tBrushDispose();
|
if (_zoomMatrix != null)
|
{
|
_zoomMatrix.Dispose();
|
_zoomMatrix = null;
|
}
|
if (this != null)
|
base.Dispose();
|
}
|
|
/// <summary>
|
/// 设置背景图像
|
/// </summary>
|
/// <param name="img"></param>
|
public void SetBackImage(Bitmap img)
|
{
|
_mEnable = false;
|
|
tBrushDispose(); //释放当前纹理
|
if (img != null)
|
{
|
_imgWidth = img.Width;
|
_imgHeight = img.Height;
|
|
//当图像的水平分辨率和垂直分辨率不为96时,将图像转换成纹理画刷之后会导致图像自动被裁剪掉一部分
|
if (img.VerticalResolution != 96 || img.HorizontalResolution != 96)
|
{
|
//重新实例化一张图片之后,新图片的水平分辨率和垂直分辨率会自动调整为96
|
using (Bitmap bmp = new Bitmap(img))
|
{
|
_tBrush = new TextureBrush(img, WrapMode.Clamp);
|
}
|
}
|
else
|
_tBrush = new TextureBrush(img, WrapMode.Clamp);
|
}
|
else
|
{
|
_imgWidth = 1;
|
_imgHeight = 1;
|
}
|
NormalMatrix();
|
_mEnable = true;
|
|
ZoomImage(parent.ClientSize.Height / 2, parent.ClientSize.Width / 2, _zoom);
|
}
|
|
/// <summary>
|
/// 缩放图像
|
/// </summary>
|
/// <param name="x">缩放的中心点X</param>
|
/// <param name="y">缩放的中心点Y</param>
|
/// <param name="zoom">缩放系数</param>
|
protected void ZoomImage(int x, int y, float zoom)
|
{
|
if (zoom >= _maxZoom)
|
zoom = _maxZoom;
|
else if (zoom < _minZoom)
|
zoom = _minZoom;
|
float oldX = x / _zoom;
|
float oldY = y / _zoom;
|
_zoom = zoom;
|
_imgX = x / zoom - oldX + _imgX;
|
_imgY = y / zoom - oldY + _imgY;
|
_zoomMatrix.Reset();
|
_zoomMatrix.Scale(zoom, zoom);
|
_zoomMatrix.Translate(_imgX, _imgY);
|
this.Refresh();
|
}
|
|
|
/// <summary>
|
/// 归一化当前矩阵
|
/// </summary>
|
protected virtual void NormalMatrix()
|
{
|
//_zoom = 1.0f;
|
//_imgX = 0.0f;
|
//_imgY = 0.0f;
|
//_zoomMatrix.Reset();
|
//_zoomMatrix.Scale(_zoom, _zoom);
|
//_zoomMatrix.Translate(_imgX, _imgY);
|
|
_zoomMatrix = new Matrix();
|
}
|
|
#endregion
|
|
#region 控件事件
|
private void _ctrl_Paint(object sender, PaintEventArgs e)
|
{
|
if (_mEnable)
|
{
|
Graphics g = e.Graphics;
|
g.InterpolationMode = InterpolationMode.HighQualityBicubic; //设置插值模式
|
if (_tBrush != null)
|
{
|
g.Transform = _zoomMatrix; //设置变换矩阵
|
g.FillRectangle(_tBrush, 0, 0, _imgWidth, _imgHeight);
|
}
|
}
|
}
|
|
private void _ctrl_MouseWheel(object sender, MouseEventArgs e)
|
{
|
if (_mEnable)
|
{
|
if (e.Delta >= 0)
|
ZoomImage(e.X, e.Y, _zoom + _mouseZoomDV);
|
else
|
ZoomImage(e.X, e.Y, _zoom - _mouseZoomDV);
|
}
|
}
|
|
private void _ctrl_MouseEnter(object sender, EventArgs e)
|
{
|
//为控件设置焦点,因为只有控件有焦点才能为控件触发鼠标滚轮事件
|
this.Focus();
|
}
|
|
private void _ctrl_MouseUp(object sender, MouseEventArgs e)
|
{
|
if (_mEnable)
|
{
|
if (e.Button == _translateBtn)
|
{
|
InTranslate = false;
|
}
|
}
|
}
|
|
private void _ctrl_MouseMove(object sender, MouseEventArgs e)
|
{
|
if (_mEnable)
|
{
|
if (_inTranslate)
|
{
|
float deltaX = e.X - _mouseDownX;
|
float deltaY = e.Y - _mouseDownY;
|
_imgX = _imgStartX + (deltaX / _zoom);
|
_imgY = _imgStartY + (deltaY / _zoom);
|
_zoomMatrix.Reset();
|
_zoomMatrix.Scale(_zoom, _zoom);
|
_zoomMatrix.Translate(_imgX, _imgY);
|
this.Refresh();
|
}
|
}
|
}
|
|
private void _ctrl_MouseDoubleDown(object sender, MouseEventArgs e)
|
{
|
if (_mEnable && _currentImage != null)
|
{
|
Bitmap Image = _currentImage.Clone() as Bitmap;
|
DisposeCurrentImage();
|
this.Image = Image;
|
}
|
}
|
|
private void _ctrl_MouseDown(object sender, MouseEventArgs e)
|
{
|
if (_mEnable)
|
{
|
if (e.Button == _translateBtn)
|
{
|
_mouseDownX = e.X;
|
_mouseDownY = e.Y;
|
_imgStartX = _imgX;
|
_imgStartY = _imgY;
|
InTranslate = true;
|
}
|
}
|
}
|
|
//private void _ctrl_MouseDoubleClick(object sender, MouseEventArgs e)
|
//{
|
// this.BeginInvoke(new Action(() =>
|
// {
|
// try
|
// {
|
// // 将 Image 保存为临时文件
|
// string tempFilePath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString() + ".jpg");
|
// this.Image.Save(tempFilePath, System.Drawing.Imaging.ImageFormat.Jpeg);
|
|
// // 使用默认图片查看器打开临时图片
|
// Process.Start(tempFilePath);
|
|
// Thread.Sleep(1000);
|
// // 在操作系统打开图片后,你可以选择删除临时文件(可选)
|
// File.Delete(tempFilePath); // 如果希望在打开后删除临时文件,取消注释此行
|
// }
|
// catch { }
|
// }));
|
//}
|
|
#endregion
|
|
#region 自定义事件
|
|
/// <summary>
|
/// 在开始平移时发生
|
/// </summary>
|
public event EventHandler StartTranslate;
|
|
/// <summary>
|
/// 在结束平移时发生
|
/// </summary>
|
public event EventHandler StopTranslate;
|
|
/// <summary>
|
/// 触发开始平移事件
|
/// </summary>
|
protected virtual void OnStartTranslate()
|
{
|
if (StartTranslate != null)
|
{
|
StartTranslate(this, EventArgs.Empty);
|
}
|
}
|
|
/// <summary>
|
/// 触发结束平移事件
|
/// </summary>
|
protected virtual void OnStopTranslate()
|
{
|
if (StopTranslate != null)
|
{
|
StopTranslate(this, EventArgs.Empty);
|
}
|
}
|
|
#endregion
|
}
|
}
|