2024-12-11 19:48:43 +08:00
|
|
|
|
|
2025-04-11 15:19:17 +08:00
|
|
|
|
using AForge.Controls;
|
2024-12-11 19:48:43 +08:00
|
|
|
|
using AForge.Imaging;
|
2025-04-11 15:19:17 +08:00
|
|
|
|
using AForge.Video;
|
2024-12-11 19:48:43 +08:00
|
|
|
|
using AForge.Video.FFMPEG;
|
2025-04-11 15:19:17 +08:00
|
|
|
|
using DirectShowLib;
|
2024-12-11 19:48:43 +08:00
|
|
|
|
using Newtonsoft.Json;
|
|
|
|
|
using Newtonsoft.Json.Linq;
|
|
|
|
|
using System;
|
|
|
|
|
using System.Collections;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.ComponentModel;
|
|
|
|
|
using System.Configuration;
|
|
|
|
|
using System.Data;
|
|
|
|
|
using System.Diagnostics;
|
|
|
|
|
using System.Drawing;
|
2025-04-11 15:19:17 +08:00
|
|
|
|
using System.Drawing.Imaging;
|
2024-12-11 19:48:43 +08:00
|
|
|
|
using System.Globalization;
|
|
|
|
|
using System.IO;
|
|
|
|
|
using System.Linq;
|
|
|
|
|
using System.Net;
|
|
|
|
|
using System.Net.Http;
|
|
|
|
|
using System.Reflection;
|
|
|
|
|
using System.Reflection.Emit;
|
|
|
|
|
using System.Runtime.InteropServices;
|
2025-04-11 15:19:17 +08:00
|
|
|
|
using System.Runtime.InteropServices.ComTypes;
|
2024-12-11 19:48:43 +08:00
|
|
|
|
using System.Security.Policy;
|
|
|
|
|
using System.Text;
|
|
|
|
|
using System.Threading;
|
|
|
|
|
using System.Threading.Tasks;
|
|
|
|
|
using System.Windows.Controls;
|
2025-04-02 23:01:04 +08:00
|
|
|
|
using System.Windows.Documents;
|
2024-12-11 19:48:43 +08:00
|
|
|
|
using System.Windows.Forms;
|
|
|
|
|
using System.Windows.Shapes;
|
2025-04-02 23:01:04 +08:00
|
|
|
|
using System.Xml.Linq;
|
2024-12-11 19:48:43 +08:00
|
|
|
|
using static AForge.Imaging.Filters.HitAndMiss;
|
|
|
|
|
using static System.Windows.Forms.VisualStyles.VisualStyleElement;
|
|
|
|
|
|
|
|
|
|
namespace videoGather
|
|
|
|
|
{
|
2025-04-11 15:19:17 +08:00
|
|
|
|
public partial class video : Form, ISampleGrabberCB
|
2024-12-11 19:48:43 +08:00
|
|
|
|
{
|
|
|
|
|
public video()
|
|
|
|
|
{
|
|
|
|
|
InitializeComponent();
|
2025-04-11 15:19:17 +08:00
|
|
|
|
InitializeOverlay(); // 初始化透明遮罩层
|
2024-12-11 19:48:43 +08:00
|
|
|
|
}
|
|
|
|
|
#region 属性
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 设备源
|
|
|
|
|
/// 用来操作摄像头
|
|
|
|
|
/// </summary>
|
|
|
|
|
private AForge.Video.DirectShow.VideoCaptureDevice videoCapture;
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 摄像头设备集合
|
|
|
|
|
/// </summary>
|
|
|
|
|
private AForge.Video.DirectShow.FilterInfoCollection infoCollection;
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 图片
|
|
|
|
|
/// </summary>
|
|
|
|
|
private System.Drawing.Bitmap imgMap;
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 文件保存路径
|
|
|
|
|
/// </summary>
|
|
|
|
|
private readonly string filePath = Application.StartupPath + @"\";
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 文件名称
|
|
|
|
|
/// </summary>
|
|
|
|
|
private readonly string fileName = $"{DateTime.Now.ToString("yyyyMMddhhmmssffff")}";
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 用与把每一帧图像写入到视频文件
|
|
|
|
|
/// </summary>
|
|
|
|
|
private AForge.Video.FFMPEG.VideoFileWriter videoWriter;
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 是否开始录像
|
|
|
|
|
/// </summary>
|
|
|
|
|
private bool IsStartVideo = false;
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 写入次数
|
|
|
|
|
/// </summary>
|
|
|
|
|
private int tick_num = 0;
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 录制多少小时,只是为了定时间计算录制时间使用
|
|
|
|
|
/// </summary>
|
|
|
|
|
private int Hour = 0;
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 计时器
|
|
|
|
|
/// </summary>
|
|
|
|
|
private System.Timers.Timer timer_count;
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 视频保存名称
|
|
|
|
|
/// </summary>
|
|
|
|
|
private string videoName = string.Empty;
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 路径地址
|
|
|
|
|
/// </summary>
|
|
|
|
|
private string _url = string.Empty;
|
|
|
|
|
|
2025-04-02 23:01:04 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// 是否读取HIS信息
|
|
|
|
|
/// </summary>
|
|
|
|
|
private string _ishisinfo = string.Empty;
|
|
|
|
|
|
2024-12-11 19:48:43 +08:00
|
|
|
|
private string _path = string.Empty;
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 当前类型
|
|
|
|
|
/// </summary>
|
|
|
|
|
private string _type = string.Empty;
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 病理截图临时存放位置
|
|
|
|
|
/// </summary>
|
|
|
|
|
private string _blpath = string.Empty;
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 病理访问前缀
|
|
|
|
|
/// </summary>
|
|
|
|
|
private string _blprefix = string.Empty;
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 病理截图热键
|
|
|
|
|
/// </summary>
|
|
|
|
|
private string strkey = string.Empty;
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 区域截图设置
|
|
|
|
|
/// </summary>
|
|
|
|
|
private string _xywh = string.Empty;
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 文件上传模式
|
|
|
|
|
/// </summary>
|
|
|
|
|
private string _model = string.Empty;
|
2025-04-02 23:01:04 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// 体检患者信息地址
|
|
|
|
|
/// </summary>
|
|
|
|
|
private string _InspectUrl = string.Empty;
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 是否开启体检编码扫码
|
|
|
|
|
/// </summary>
|
|
|
|
|
private string _isInspect = string.Empty;
|
2025-04-11 15:19:17 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// 是否开启区域截图
|
|
|
|
|
/// </summary>
|
|
|
|
|
private string _isselectionXY = string.Empty;
|
|
|
|
|
|
2024-12-11 19:48:43 +08:00
|
|
|
|
//超声存放文件访问地址
|
|
|
|
|
ArrayList imagearray = new ArrayList();
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 存放双击选择的患者数据
|
|
|
|
|
/// </summary>
|
|
|
|
|
private HisInfo rowhisinfo;
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 存放自己新增的数据源
|
|
|
|
|
/// </summary>
|
|
|
|
|
List<HisInfo> hisInfos = new List<HisInfo>();
|
2025-04-11 15:19:17 +08:00
|
|
|
|
|
|
|
|
|
AForge.Controls.VideoSourcePlayer player;
|
|
|
|
|
|
|
|
|
|
#region 新的方式
|
|
|
|
|
DsDevice device1;
|
|
|
|
|
private int _pWidth = 1280;
|
|
|
|
|
private int _pHeight = 720;
|
|
|
|
|
private int _pStride = 0;
|
|
|
|
|
private int _pFPS = 30;
|
|
|
|
|
private volatile bool isGrab = false;
|
|
|
|
|
|
|
|
|
|
IVideoWindow videoWindow = null;
|
|
|
|
|
IMediaControl mediaControl = null;
|
|
|
|
|
IFilterGraph2 graphBuilder = null;
|
|
|
|
|
ICaptureGraphBuilder2 captureGraphBuilder = null;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
DsROTEntry rot = null;
|
|
|
|
|
|
|
|
|
|
DsDevice[] devices;
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region 选区
|
|
|
|
|
// 类成员变量声明
|
|
|
|
|
private System.Drawing.Rectangle selectionRect; // 存储当前选区矩形
|
|
|
|
|
private Point startPoint; // 选区起始坐标点
|
|
|
|
|
private bool isSelecting; // 是否处于选区状态标志
|
|
|
|
|
private DoubleBufferedPanel overlayPanel; // 透明遮罩层控件
|
|
|
|
|
#endregion
|
|
|
|
|
|
2024-12-11 19:48:43 +08:00
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region 窗口加载与关闭
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 讲题加载事件
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="sender"></param>
|
|
|
|
|
/// <param name="e"></param>
|
|
|
|
|
private void Form1_Load(object sender, EventArgs e)
|
|
|
|
|
{
|
2025-04-11 15:19:17 +08:00
|
|
|
|
// _pWidth = pictureBox1.Width;
|
|
|
|
|
// _pHeight = pictureBox1.Height;
|
2024-12-11 19:48:43 +08:00
|
|
|
|
dGVPatient.AutoGenerateColumns = false;
|
|
|
|
|
|
2025-04-11 15:19:17 +08:00
|
|
|
|
// InitCamera();
|
2024-12-11 19:48:43 +08:00
|
|
|
|
InitCameraSelect();
|
|
|
|
|
//读取配置信息
|
2025-04-02 23:01:04 +08:00
|
|
|
|
_isInspect = ConfigurationManager.AppSettings["isInspect"];
|
|
|
|
|
_InspectUrl = ConfigurationManager.AppSettings["InspectUrl"];
|
2024-12-11 19:48:43 +08:00
|
|
|
|
_url = ConfigurationManager.AppSettings["URL"];
|
|
|
|
|
_path = ConfigurationManager.AppSettings["path"];
|
|
|
|
|
_type = ConfigurationManager.AppSettings["type"];
|
|
|
|
|
_blpath = ConfigurationManager.AppSettings["blpath"];
|
|
|
|
|
strkey = ConfigurationManager.AppSettings["strkey"];
|
|
|
|
|
_blprefix = ConfigurationManager.AppSettings["blprefix"];
|
|
|
|
|
_xywh = ConfigurationManager.AppSettings["xywh"];
|
|
|
|
|
_model = ConfigurationManager.AppSettings["model"];
|
2025-04-02 23:01:04 +08:00
|
|
|
|
_ishisinfo = ConfigurationManager.AppSettings["ishisinfo"];
|
2025-04-11 15:19:17 +08:00
|
|
|
|
_isselectionXY = ConfigurationManager.AppSettings["isselectionXY"];
|
2024-12-11 19:48:43 +08:00
|
|
|
|
if (_type == "1")
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
gb_ButtonBox.Visible = true;
|
|
|
|
|
groupBox2.Visible = false;
|
|
|
|
|
}
|
|
|
|
|
else if (_type == "2")
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
gb_ButtonBox.Visible = false;
|
|
|
|
|
groupBox2.Visible = true;
|
|
|
|
|
|
|
|
|
|
txt_x.Enabled = false;
|
|
|
|
|
txt_y.Enabled = false;
|
|
|
|
|
txt_w.Enabled = false;
|
|
|
|
|
txt_h.Enabled = false;
|
|
|
|
|
txt_x.Text = _xywh.Split(',')[0];
|
|
|
|
|
txt_y.Text = _xywh.Split(',')[1];
|
|
|
|
|
txt_w.Text = _xywh.Split(',')[2];
|
|
|
|
|
txt_h.Text = _xywh.Split(',')[3];
|
|
|
|
|
}
|
|
|
|
|
this.btn_Capture.Enabled = false;
|
2025-04-02 23:01:04 +08:00
|
|
|
|
if (_isInspect == "1")
|
|
|
|
|
{
|
|
|
|
|
label7.Visible = true;
|
|
|
|
|
textBox1.Visible = true;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
label7.Visible = false;
|
|
|
|
|
textBox1.Visible = false;
|
|
|
|
|
}
|
2025-04-11 15:19:17 +08:00
|
|
|
|
if (_isselectionXY=="1")
|
|
|
|
|
{
|
|
|
|
|
button7.Visible = true;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
button7.Visible = false;
|
|
|
|
|
}
|
|
|
|
|
// 启用双缓冲减少闪烁
|
|
|
|
|
typeof(System.Windows.Forms.PictureBox).InvokeMember("DoubleBuffered",
|
|
|
|
|
BindingFlags.SetProperty | BindingFlags.Instance | BindingFlags.NonPublic,
|
|
|
|
|
null, pictureBox1, new object[] { true });
|
2024-12-11 19:48:43 +08:00
|
|
|
|
|
|
|
|
|
//秒表
|
|
|
|
|
timer_count = new System.Timers.Timer(); //实例化Timer类,设置间隔时间为1000毫秒;
|
|
|
|
|
timer_count.Elapsed += new System.Timers.ElapsedEventHandler(tick_count); //到达时间的时候执行事件;
|
|
|
|
|
timer_count.AutoReset = true; //设置是执行一次(false)还是一直执行(true);
|
|
|
|
|
timer_count.Interval = 1000;
|
|
|
|
|
HookStart();
|
|
|
|
|
btn_Connect_Click(null, null);
|
2025-04-02 23:01:04 +08:00
|
|
|
|
if (_ishisinfo == "0")
|
|
|
|
|
{
|
|
|
|
|
button1.Visible = true;
|
|
|
|
|
GetHisInfo();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
button1.Visible = false;
|
|
|
|
|
}
|
2024-12-11 19:48:43 +08:00
|
|
|
|
label4.Focus();
|
2025-04-02 23:01:04 +08:00
|
|
|
|
// 添加对窗口大小改变事件的订阅
|
2025-04-11 15:19:17 +08:00
|
|
|
|
// this.Resize += new EventHandler(Form1_Resize);
|
2025-04-02 23:01:04 +08:00
|
|
|
|
}
|
|
|
|
|
|
2025-04-11 15:19:17 +08:00
|
|
|
|
#region 初始化透明遮罩层
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 初始化透明遮罩层
|
|
|
|
|
/// </summary>
|
|
|
|
|
private void InitializeOverlay()
|
|
|
|
|
{
|
|
|
|
|
// 创建透明遮罩层
|
|
|
|
|
overlayPanel = new DoubleBufferedPanel
|
|
|
|
|
{
|
|
|
|
|
// 设置与 PictureBox 相同的尺寸和位置
|
|
|
|
|
// Size = pictureBox1.Size,
|
|
|
|
|
Location = pictureBox1.Location,
|
|
|
|
|
// 设置透明背景
|
|
|
|
|
BackColor = Color.FromArgb(0, 0, 0, 0),
|
|
|
|
|
// 设置十字光标
|
|
|
|
|
Cursor = Cursors.Cross,
|
|
|
|
|
// 初始不可见
|
|
|
|
|
Visible = false,
|
|
|
|
|
Width= 1280,
|
|
|
|
|
Height=720
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 将遮罩层添加到PictureBox的父容器(确保层级正确)
|
|
|
|
|
pictureBox1.Parent.Controls.Add(overlayPanel);
|
|
|
|
|
// 置于顶层,保证在视频上方显示
|
|
|
|
|
overlayPanel.BringToFront();
|
|
|
|
|
|
|
|
|
|
// 绑定事件处理器
|
|
|
|
|
overlayPanel.MouseDown += Overlay_MouseDown;
|
|
|
|
|
overlayPanel.MouseMove += Overlay_MouseMove;
|
|
|
|
|
overlayPanel.MouseUp += Overlay_MouseUp;
|
|
|
|
|
overlayPanel.Paint += Overlay_Paint;
|
|
|
|
|
}
|
|
|
|
|
#endregion
|
2025-04-02 23:01:04 +08:00
|
|
|
|
private void Form1_Resize(object sender, EventArgs e)
|
|
|
|
|
{
|
|
|
|
|
//// 检查视频捕获是否已初始化
|
|
|
|
|
//if (videoCapture != null && videoCapture.IsRunning)
|
|
|
|
|
//{
|
|
|
|
|
// // 停止并重新启动视频捕获,确保视频帧能够正确显示
|
|
|
|
|
// videoCapture.SignalToStop();
|
|
|
|
|
// videoCapture.WaitForStop();
|
|
|
|
|
// videoCapture.Start();
|
|
|
|
|
//}
|
|
|
|
|
|
|
|
|
|
// 检查视频捕获是否已初始化
|
|
|
|
|
if (videoCapture != null)
|
|
|
|
|
{
|
|
|
|
|
if (this.WindowState == FormWindowState.Minimized)
|
|
|
|
|
{
|
|
|
|
|
// 窗口最小化时停止视频捕获
|
|
|
|
|
if (videoCapture.IsRunning)
|
|
|
|
|
{
|
|
|
|
|
videoCapture.SignalToStop();
|
|
|
|
|
videoCapture.WaitForStop();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (this.WindowState == FormWindowState.Maximized || this.WindowState == FormWindowState.Normal)
|
|
|
|
|
{
|
|
|
|
|
// 窗口最大化或恢复正常大小时重新启动视频捕获
|
|
|
|
|
if (!videoCapture.IsRunning)
|
|
|
|
|
{
|
|
|
|
|
videoCapture.Start();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-12-11 19:48:43 +08:00
|
|
|
|
}
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 窗口关闭时
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="sender"></param>
|
|
|
|
|
/// <param name="e"></param>
|
|
|
|
|
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
|
|
|
|
|
{
|
2025-04-11 15:19:17 +08:00
|
|
|
|
// EndCamera();
|
|
|
|
|
StopCamera();
|
2024-12-11 19:48:43 +08:00
|
|
|
|
}
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region 实例化
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 实例化摄像头
|
|
|
|
|
/// </summary>
|
|
|
|
|
public void InitCamera()
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
//检测电脑上的摄像头设备
|
|
|
|
|
infoCollection = new AForge.Video.DirectShow.FilterInfoCollection(AForge.Video.DirectShow.FilterCategory.VideoInputDevice);
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
MessageBox.Show($"没有找到设备:{ex.Message}", "Error");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
//加载摄像头选择
|
|
|
|
|
public void InitCameraSelect()
|
|
|
|
|
{
|
|
|
|
|
this.cb_CameraSelect.DropDownStyle = ComboBoxStyle.DropDownList;
|
2025-04-11 15:19:17 +08:00
|
|
|
|
////根据读取到的摄像头加载选择项
|
|
|
|
|
//foreach (AForge.Video.DirectShow.FilterInfo item in infoCollection)
|
|
|
|
|
//{
|
|
|
|
|
// this.cb_CameraSelect.Items.Add(item.Name);
|
|
|
|
|
//}
|
|
|
|
|
////for (int i = 1; i <= infoCollection.Count; i++)
|
|
|
|
|
////{
|
|
|
|
|
//// this.cb_CameraSelect.Items.Add("摄像头" + i);
|
|
|
|
|
////}
|
|
|
|
|
//if (cb_CameraSelect.Items.Count > 0)
|
2024-12-11 19:48:43 +08:00
|
|
|
|
//{
|
2025-04-11 15:19:17 +08:00
|
|
|
|
// cb_CameraSelect.SelectedIndex = 0;
|
2024-12-11 19:48:43 +08:00
|
|
|
|
//}
|
2025-04-11 15:19:17 +08:00
|
|
|
|
|
|
|
|
|
devices = DsDevice.GetDevicesOfCat(FilterCategory.VideoInputDevice);
|
|
|
|
|
for (int i = 0; i < devices.Length; i++)
|
|
|
|
|
{
|
|
|
|
|
this.cb_CameraSelect.Items.Add(devices[i].Name);
|
|
|
|
|
|
|
|
|
|
}
|
2024-12-11 19:48:43 +08:00
|
|
|
|
if (cb_CameraSelect.Items.Count > 0)
|
|
|
|
|
{
|
2025-04-11 15:19:17 +08:00
|
|
|
|
cb_CameraSelect.SelectedIndex = 1;
|
|
|
|
|
//}
|
2024-12-11 19:48:43 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region 连接读取与关闭
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 连接按钮
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="sender"></param>
|
|
|
|
|
/// <param name="e"></param>
|
|
|
|
|
private void btn_Connect_Click(object sender, EventArgs e)
|
|
|
|
|
{
|
2025-04-11 15:19:17 +08:00
|
|
|
|
// var CameraSelect = this.cb_CameraSelect.Text;
|
|
|
|
|
// var selectIndex = this.cb_CameraSelect.SelectedIndex;
|
|
|
|
|
// if (string.IsNullOrEmpty(CameraSelect))
|
|
|
|
|
// {
|
|
|
|
|
// MessageBox.Show("请先选择视频源");
|
|
|
|
|
// return;
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// //已有连接的摄像头时先关闭
|
|
|
|
|
// if (videoCapture != null)
|
|
|
|
|
// {
|
|
|
|
|
// EndCamera();
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// player = new VideoSourcePlayer();
|
|
|
|
|
// player.Dock = DockStyle.Fill;
|
|
|
|
|
// gb_CameraPanel.Controls.Add(player);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// videoCapture = new AForge.Video.DirectShow.VideoCaptureDevice(infoCollection[selectIndex].MonikerString);
|
|
|
|
|
// videoCapture.VideoResolution = videoCapture.VideoCapabilities
|
|
|
|
|
//.OrderBy(x => x.MaximumFrameRate)
|
|
|
|
|
//.FirstOrDefault();
|
|
|
|
|
|
|
|
|
|
// //启动摄像头
|
|
|
|
|
// player.VideoSource = videoCapture;
|
|
|
|
|
// player.Start();
|
|
|
|
|
// // videoCapture.Start();
|
|
|
|
|
// //this.vsp_Panel.VideoSource.NewFrame += videoCapture_NewFrame;
|
|
|
|
|
// //this.vsp_Panel.VideoSource.
|
|
|
|
|
|
|
|
|
|
StopCamera();
|
|
|
|
|
// 调用前检查
|
|
|
|
|
if (!ValidateResolution(_pWidth, _pHeight))
|
|
|
|
|
{
|
|
|
|
|
MessageBox.Show("不支持的视频分辨率");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (devices.Length == 0)
|
2024-12-11 19:48:43 +08:00
|
|
|
|
{
|
2025-04-11 15:19:17 +08:00
|
|
|
|
MessageBox.Show("无视频源");
|
2024-12-11 19:48:43 +08:00
|
|
|
|
return;
|
|
|
|
|
}
|
2025-04-11 15:19:17 +08:00
|
|
|
|
else
|
2024-12-11 19:48:43 +08:00
|
|
|
|
{
|
2025-04-11 15:19:17 +08:00
|
|
|
|
DsDevice ds=null;
|
|
|
|
|
foreach (var item in devices)
|
|
|
|
|
{
|
|
|
|
|
if(item.Name== this.cb_CameraSelect.SelectedItem)
|
|
|
|
|
{
|
|
|
|
|
ds = item;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CaptureVideo(ds);
|
2024-12-11 19:48:43 +08:00
|
|
|
|
}
|
|
|
|
|
this.btn_Capture.Enabled = true;
|
2025-04-11 15:19:17 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 检查是否支持分辨率
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="width"></param>
|
|
|
|
|
/// <param name="height"></param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
private bool ValidateResolution(int width, int height)
|
|
|
|
|
{
|
|
|
|
|
// 检查是否为设备支持的分辨率
|
|
|
|
|
var supportedResolutions = new[] {
|
|
|
|
|
new Size(640, 480),
|
|
|
|
|
new Size(1280, 720),
|
|
|
|
|
new Size(1920, 1080)
|
|
|
|
|
};
|
|
|
|
|
return supportedResolutions.Any(s => s.Width == width && s.Height == height);
|
2024-12-11 19:48:43 +08:00
|
|
|
|
}
|
2025-04-11 15:19:17 +08:00
|
|
|
|
|
|
|
|
|
|
2024-12-11 19:48:43 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// 关闭按钮
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="sender"></param>
|
|
|
|
|
/// <param name="e"></param>
|
|
|
|
|
private void btn_Close_Click(object sender, EventArgs e)
|
|
|
|
|
{
|
|
|
|
|
HookStop();
|
2025-04-11 15:19:17 +08:00
|
|
|
|
// EndCamera();
|
|
|
|
|
StopCamera();
|
2024-12-11 19:48:43 +08:00
|
|
|
|
}
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 关闭摄像头
|
|
|
|
|
/// </summary>
|
|
|
|
|
public void EndCamera()
|
|
|
|
|
{
|
2025-04-11 15:19:17 +08:00
|
|
|
|
if (videoCapture != null)
|
2024-12-11 19:48:43 +08:00
|
|
|
|
{
|
2025-04-11 15:19:17 +08:00
|
|
|
|
// 先移除事件处理器
|
|
|
|
|
// this.vsp_Panel.VideoSource.NewFrame -= videoCapture_NewFrame;
|
|
|
|
|
if (player!=null)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
videoCapture.SignalToStop();
|
|
|
|
|
videoCapture.WaitForStop();
|
|
|
|
|
videoCapture.Stop();
|
|
|
|
|
|
|
|
|
|
// 停止视频源
|
|
|
|
|
player.SignalToStop();
|
|
|
|
|
player.WaitForStop();
|
|
|
|
|
player.Stop();
|
|
|
|
|
gb_CameraPanel.Controls.Clear();
|
|
|
|
|
videoCapture = null;
|
|
|
|
|
player = null;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
2024-12-11 19:48:43 +08:00
|
|
|
|
|
|
|
|
|
}
|
2025-04-11 15:19:17 +08:00
|
|
|
|
//if (this.vsp_Panel.VideoSource != null)
|
|
|
|
|
//{
|
|
|
|
|
// //也可以用 Stop() 方法关闭
|
|
|
|
|
// //指示灯停止且等待
|
|
|
|
|
// //this.vsp_Panel.SignalToStop();
|
|
|
|
|
// ////停止且等待
|
|
|
|
|
// //this.vsp_Panel.WaitForStop();
|
|
|
|
|
// //this.vsp_Panel.VideoSource = null;
|
|
|
|
|
// // this.vsp_Panel.Stop();
|
|
|
|
|
// // this.vsp_Panel.Dispose();
|
|
|
|
|
// // this.vsp_Panel.VideoSource = null;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//}
|
2024-12-11 19:48:43 +08:00
|
|
|
|
}
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region 拍照与保存
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 拍照
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="sender"></param>
|
|
|
|
|
/// <param name="e"></param>
|
|
|
|
|
private void btn_Capture_Click(object sender, EventArgs e)
|
|
|
|
|
{
|
2025-04-02 23:01:04 +08:00
|
|
|
|
try
|
2024-12-11 19:48:43 +08:00
|
|
|
|
{
|
2025-04-11 15:19:17 +08:00
|
|
|
|
#region 之前
|
|
|
|
|
//if (videoCapture == null)
|
|
|
|
|
//{
|
|
|
|
|
// MessageBox.Show("设备未连接");
|
|
|
|
|
// return;
|
|
|
|
|
//}
|
|
|
|
|
//imgMap = player.GetCurrentVideoFrame();
|
|
|
|
|
//if (imgMap == null)
|
|
|
|
|
//{
|
|
|
|
|
// return;
|
|
|
|
|
//}
|
|
|
|
|
//var saveName = $"{filePath}{$"{DateTime.Now.ToString("yyyyMMddhhmmssffff")}"}.jpg";
|
|
|
|
|
//imgMap.Save(saveName);
|
|
|
|
|
//imgMap = null;
|
|
|
|
|
//imagearray.Add(saveName);
|
|
|
|
|
//// 使用 Invoke 方法确保在UI线程上更新标签的文本
|
|
|
|
|
//if (label1.InvokeRequired)
|
|
|
|
|
//{
|
|
|
|
|
// label1.Invoke(new Action(() => label1.Text = imagearray.Count.ToString()));
|
|
|
|
|
//}
|
|
|
|
|
//else
|
|
|
|
|
//{
|
|
|
|
|
// label1.Text = imagearray.Count.ToString();
|
|
|
|
|
//}
|
|
|
|
|
//label1.Refresh();
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
isGrab = true;
|
2024-12-11 19:48:43 +08:00
|
|
|
|
}
|
2025-04-02 23:01:04 +08:00
|
|
|
|
catch (Exception ex)
|
2024-12-11 19:48:43 +08:00
|
|
|
|
{
|
2025-04-02 23:01:04 +08:00
|
|
|
|
MessageBox.Show(ex.Message+ex.StackTrace);
|
2024-12-11 19:48:43 +08:00
|
|
|
|
}
|
2025-04-02 23:01:04 +08:00
|
|
|
|
|
2024-12-11 19:48:43 +08:00
|
|
|
|
}
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 保存事件
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="sender"></param>
|
|
|
|
|
/// <param name="e"></param>
|
|
|
|
|
private void btn_Save_Click(object sender, EventArgs e)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region 录像
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 开始录像
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="sender"></param>
|
|
|
|
|
/// <param name="e"></param>
|
|
|
|
|
private void btn_StartVideo_Click(object sender, EventArgs e)
|
|
|
|
|
{
|
|
|
|
|
if (videoCapture == null)
|
|
|
|
|
{
|
|
|
|
|
MessageBox.Show("设备未连接");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (rowhisinfo == null)
|
|
|
|
|
{
|
|
|
|
|
MessageBox.Show("请选择患者");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
btn_StartVideo.Enabled = false;
|
|
|
|
|
videoName = $"{filePath}{fileName}.mp4";
|
|
|
|
|
IsStartVideo = true;
|
|
|
|
|
//开始计时
|
|
|
|
|
timer_count.Enabled = true;
|
|
|
|
|
//配置录像参数(宽,高,帧率,比特率等参数)VideoCapabilities这个属性会返回摄像头支持哪些配置,从这里面选一个赋值接即可
|
|
|
|
|
videoCapture.VideoResolution = videoCapture.VideoCapabilities[0];
|
|
|
|
|
//设置回调,aforge会不断从这个回调推出图像数据
|
|
|
|
|
videoCapture.NewFrame += Camera_NewFrame;
|
|
|
|
|
videoWriter = new AForge.Video.FFMPEG.VideoFileWriter();
|
|
|
|
|
//打开摄像头
|
|
|
|
|
//videoCapture.Start();
|
|
|
|
|
int videoBitrate = 5000000; // 1000 Kbps
|
|
|
|
|
//打开录像文件(如果没有则创建,如果有也会清空),这里还有关于视频宽高、帧率、格式、比特率
|
|
|
|
|
videoWriter.Open(
|
|
|
|
|
videoName,
|
|
|
|
|
videoCapture.VideoResolution.FrameSize.Width,
|
|
|
|
|
videoCapture.VideoResolution.FrameSize.Height,
|
|
|
|
|
videoCapture.VideoResolution.AverageFrameRate,
|
|
|
|
|
AForge.Video.FFMPEG.VideoCodec.MPEG4,
|
|
|
|
|
videoBitrate
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
//this.lab_Time
|
|
|
|
|
//摄像头输出回调
|
|
|
|
|
private void Camera_NewFrame(object sender, AForge.Video.NewFrameEventArgs eventArgs)
|
|
|
|
|
{
|
|
|
|
|
imgMap = eventArgs.Frame;
|
|
|
|
|
lock (imgMap)
|
|
|
|
|
{
|
|
|
|
|
if (eventArgs != null && eventArgs.Frame != null)
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
//写到文件
|
|
|
|
|
videoWriter.WriteVideoFrame(eventArgs.Frame);
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
//MessageBox.Show("写入文件错误"+ex.Message);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 暂停录像
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="sender"></param>
|
|
|
|
|
/// <param name="e"></param>
|
|
|
|
|
private void btn_PauseVideo_Click(object sender, EventArgs e)
|
|
|
|
|
{
|
|
|
|
|
if (videoCapture == null)
|
|
|
|
|
{
|
|
|
|
|
MessageBox.Show("设备未连接");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
var stopBtnName = this.btn_PauseVideo.Text;
|
|
|
|
|
if (stopBtnName == "暂停录像")
|
|
|
|
|
{
|
|
|
|
|
this.btn_PauseVideo.Text = "恢复录像";
|
|
|
|
|
//暂停计时
|
|
|
|
|
timer_count.Enabled = false;
|
|
|
|
|
IsStartVideo = false;
|
|
|
|
|
}
|
|
|
|
|
if (stopBtnName == "恢复录像")
|
|
|
|
|
{
|
|
|
|
|
this.btn_PauseVideo.Text = "暂停录像";
|
|
|
|
|
//恢复计时
|
|
|
|
|
timer_count.Enabled = true;
|
|
|
|
|
IsStartVideo = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 停止录像
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="sender"></param>
|
|
|
|
|
/// <param name="e"></param>
|
|
|
|
|
private void btn_EndVideo_Click(object sender, EventArgs e)
|
|
|
|
|
{
|
|
|
|
|
if (videoCapture == null)
|
|
|
|
|
{
|
|
|
|
|
MessageBox.Show("设备未连接");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
btn_StartVideo.Enabled = true;
|
|
|
|
|
IsStartVideo = false;
|
|
|
|
|
timer_count.Enabled = false;
|
|
|
|
|
if (videoWriter != null)
|
|
|
|
|
{
|
|
|
|
|
videoWriter.Close();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
tick_num = 0;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region 计时器响应函数
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 计时器
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="source"></param>
|
|
|
|
|
/// <param name="e"></param>
|
|
|
|
|
public void tick_count(object source, System.Timers.ElapsedEventArgs e)
|
|
|
|
|
{
|
|
|
|
|
tick_num++;
|
|
|
|
|
int Temp = tick_num;
|
|
|
|
|
int Second = Temp % 60;
|
|
|
|
|
int Minute = Temp / 60;
|
|
|
|
|
if (Minute % 60 == 0)
|
|
|
|
|
{
|
|
|
|
|
Hour = Minute / 60;
|
|
|
|
|
Minute = 0;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
Minute = Minute - Hour * 60;
|
|
|
|
|
}
|
|
|
|
|
string HourStr = Hour < 10 ? $"0{Hour}" : Hour.ToString();
|
|
|
|
|
string MinuteStr = Minute < 10 ? $"0{Minute}" : Minute.ToString();
|
|
|
|
|
string SecondStr = Second < 10 ? $"0{Second}" : Second.ToString();
|
|
|
|
|
String tick = $"{HourStr}:{MinuteStr}:{SecondStr}";
|
|
|
|
|
this.Invoke((EventHandler)(delegate
|
|
|
|
|
{
|
|
|
|
|
this.lab_Time.Text = tick;
|
|
|
|
|
}));
|
|
|
|
|
}
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 视频上传
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="sender"></param>
|
|
|
|
|
/// <param name="e"></param>
|
|
|
|
|
private void button1_Click(object sender, EventArgs e)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#region 请求接口
|
|
|
|
|
|
|
|
|
|
private void UploadFileUrl(string filename, string filetype)
|
|
|
|
|
{
|
|
|
|
|
if (!string.IsNullOrEmpty(filename) && !string.IsNullOrEmpty(filetype))
|
|
|
|
|
{
|
|
|
|
|
string imgType = "1";//1图片2 视频
|
|
|
|
|
string ID = string.Empty;
|
|
|
|
|
string imagebase = string.Empty;
|
|
|
|
|
string imgDescription = "超声图像";
|
|
|
|
|
string orgId = string.Empty;
|
|
|
|
|
if (filetype == ".mp4")
|
|
|
|
|
{
|
|
|
|
|
imgType = "2";
|
|
|
|
|
imgDescription = "超声视频";
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
imagebase = _path + @"/" + rowhisinfo.jianchaid + "/" + filename;
|
|
|
|
|
ID = rowhisinfo.jianchaid;
|
|
|
|
|
orgId = rowhisinfo.yiyuancode;
|
|
|
|
|
insimagescreenshotVO vO = new insimagescreenshotVO();
|
|
|
|
|
vO.id = ID;
|
|
|
|
|
vO.imagebase = imagebase;
|
|
|
|
|
vO.imgDescription = imgDescription;
|
|
|
|
|
vO.imgType = imgType;
|
|
|
|
|
vO.orgId = orgId;
|
|
|
|
|
var json = JsonConvert.SerializeObject(vO);
|
|
|
|
|
string msg = Post(_url + "/admin-api/ultrasoniccom/ultrasonic/insimagescreenshot", json);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 指定Post地址使用Get 方式获取全部字符串
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="url">请求后台地址</param>
|
|
|
|
|
/// <param name="content">Post提交数据内容(utf-8编码的)</param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
public static string Post(string url, string content)
|
|
|
|
|
{
|
|
|
|
|
string result = "";
|
|
|
|
|
try
|
|
|
|
|
{
|
2025-04-02 23:01:04 +08:00
|
|
|
|
// 忽略证书验证
|
|
|
|
|
ServicePointManager.ServerCertificateValidationCallback += (sender, certificate, chain, sslPolicyErrors) => true;
|
2024-12-11 19:48:43 +08:00
|
|
|
|
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(url);
|
|
|
|
|
req.Method = "POST";
|
|
|
|
|
req.ContentType = "application/json";
|
|
|
|
|
|
|
|
|
|
#region 添加Post 参数
|
|
|
|
|
byte[] data = Encoding.UTF8.GetBytes(content);
|
|
|
|
|
req.ContentLength = data.Length;
|
|
|
|
|
using (Stream reqStream = req.GetRequestStream())
|
|
|
|
|
{
|
|
|
|
|
reqStream.Write(data, 0, data.Length);
|
|
|
|
|
reqStream.Close();
|
|
|
|
|
}
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
HttpWebResponse resp = (HttpWebResponse)req.GetResponse();
|
|
|
|
|
Stream stream = resp.GetResponseStream();
|
|
|
|
|
//获取响应内容
|
|
|
|
|
using (StreamReader reader = new StreamReader(stream, Encoding.UTF8))
|
|
|
|
|
{
|
|
|
|
|
result = reader.ReadToEnd();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
MessageBox.Show(ex.Message);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 指定Post地址使用Get 方式获取全部字符串
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="url">请求后台地址</param>
|
|
|
|
|
/// <param name="content">Post提交数据内容(utf-8编码的)</param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
public static string Post(string url, string content, string headerKey, string headerValue)
|
|
|
|
|
{
|
|
|
|
|
string result = "";
|
|
|
|
|
try
|
|
|
|
|
{
|
2025-04-02 23:01:04 +08:00
|
|
|
|
// 忽略证书验证
|
|
|
|
|
ServicePointManager.ServerCertificateValidationCallback += (sender, certificate, chain, sslPolicyErrors) => true;
|
2024-12-11 19:48:43 +08:00
|
|
|
|
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(url);
|
|
|
|
|
req.Method = "POST";
|
|
|
|
|
req.ContentType = "application/json";
|
|
|
|
|
req.Headers[headerKey] = headerValue;
|
|
|
|
|
#region 添加Post 参数
|
|
|
|
|
byte[] data = Encoding.UTF8.GetBytes(content);
|
|
|
|
|
req.ContentLength = data.Length;
|
|
|
|
|
using (Stream reqStream = req.GetRequestStream())
|
|
|
|
|
{
|
|
|
|
|
reqStream.Write(data, 0, data.Length);
|
|
|
|
|
reqStream.Close();
|
|
|
|
|
}
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
HttpWebResponse resp = (HttpWebResponse)req.GetResponse();
|
|
|
|
|
Stream stream = resp.GetResponseStream();
|
|
|
|
|
//获取响应内容
|
|
|
|
|
using (StreamReader reader = new StreamReader(stream, Encoding.UTF8))
|
|
|
|
|
{
|
|
|
|
|
result = reader.ReadToEnd();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
MessageBox.Show(ex.Message);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Get请求
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="url">请求url</param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
public static string Get(string url)
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
2025-04-02 23:01:04 +08:00
|
|
|
|
// 忽略证书验证
|
|
|
|
|
ServicePointManager.ServerCertificateValidationCallback += (sender, certificate, chain, sslPolicyErrors) => true;
|
2024-12-11 19:48:43 +08:00
|
|
|
|
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(url);
|
|
|
|
|
req.Method = "GET";
|
|
|
|
|
req.Timeout = 30000;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (req == null || req.GetResponse() == null)
|
|
|
|
|
{
|
|
|
|
|
MessageBox.Show("请求对象为空");
|
|
|
|
|
return string.Empty;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
HttpWebResponse resp = (HttpWebResponse)req.GetResponse();
|
|
|
|
|
if (resp == null)
|
|
|
|
|
{
|
|
|
|
|
MessageBox.Show("响应对象为空");
|
|
|
|
|
return string.Empty;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
using (var stream = resp.GetResponseStream())
|
|
|
|
|
using (var reader = new StreamReader(stream, Encoding.UTF8))
|
|
|
|
|
{
|
|
|
|
|
var content = new StringBuilder();
|
|
|
|
|
char[] buffer = new char[1024];
|
|
|
|
|
int read;
|
|
|
|
|
while ((read = reader.Read(buffer, 0, buffer.Length)) > 0)
|
|
|
|
|
{
|
|
|
|
|
content.Append(new string(buffer, 0, read));
|
|
|
|
|
}
|
|
|
|
|
return content.ToString();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
MessageBox.Show("发生错误: " + ex.Message);
|
|
|
|
|
return string.Empty;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Get请求
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="url"></param>
|
|
|
|
|
/// <param name="headerKey"></param>
|
|
|
|
|
/// <param name="headerValue"></param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
public static string Get(string url, string headerKey, string headerValue)
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
2025-04-02 23:01:04 +08:00
|
|
|
|
// 忽略证书验证
|
|
|
|
|
ServicePointManager.ServerCertificateValidationCallback += (sender, certificate, chain, sslPolicyErrors) => true;
|
2024-12-11 19:48:43 +08:00
|
|
|
|
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(url);
|
|
|
|
|
req.Method = "GET";
|
|
|
|
|
req.Timeout = 30000;
|
|
|
|
|
|
|
|
|
|
req.Headers[headerKey] = headerValue;
|
|
|
|
|
|
|
|
|
|
if (req == null || req.GetResponse() == null)
|
|
|
|
|
{
|
|
|
|
|
MessageBox.Show("请求对象为空");
|
|
|
|
|
return string.Empty;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
HttpWebResponse resp = (HttpWebResponse)req.GetResponse();
|
|
|
|
|
if (resp == null)
|
|
|
|
|
{
|
|
|
|
|
MessageBox.Show("响应对象为空");
|
|
|
|
|
return string.Empty;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
using (var stream = resp.GetResponseStream())
|
|
|
|
|
using (var reader = new StreamReader(stream, Encoding.UTF8))
|
|
|
|
|
{
|
|
|
|
|
var content = new StringBuilder();
|
|
|
|
|
char[] buffer = new char[1024];
|
|
|
|
|
int read;
|
|
|
|
|
while ((read = reader.Read(buffer, 0, buffer.Length)) > 0)
|
|
|
|
|
{
|
|
|
|
|
content.Append(new string(buffer, 0, read));
|
|
|
|
|
}
|
|
|
|
|
return content.ToString();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
MessageBox.Show("发生错误: " + ex.Message);
|
|
|
|
|
return string.Empty;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 获取HIS患者信息
|
|
|
|
|
/// </summary>
|
|
|
|
|
public void GetHisInfo()
|
|
|
|
|
{
|
2025-04-02 23:01:04 +08:00
|
|
|
|
try
|
2024-12-11 19:48:43 +08:00
|
|
|
|
{
|
2025-04-02 23:01:04 +08:00
|
|
|
|
//存放绑定界面的患者数据 一个患者有多个检查 按照检查拆分 一个检查一条数据
|
|
|
|
|
List<HisInfo> hisInfos = new List<HisInfo>();
|
|
|
|
|
//获取福乐云HIS接口的token
|
|
|
|
|
string hisToken = getHisToken(ConfigurationManager.AppSettings["hisGetTokenUrl"], ConfigurationManager.AppSettings["hisAppkey"], ConfigurationManager.AppSettings["appsecret"]);
|
|
|
|
|
|
|
|
|
|
//获取当天的患者信息
|
|
|
|
|
FlyHisEcgDataModel FHEDM = GetHisEcgData(ConfigurationManager.AppSettings["hisGetDataUrl"], ConfigurationManager.AppSettings["inHisCode"], DateTime.Now.ToString("yyyy-MM-dd"), hisToken);//
|
|
|
|
|
if (FHEDM != null)
|
2024-12-11 19:48:43 +08:00
|
|
|
|
{
|
2025-04-02 23:01:04 +08:00
|
|
|
|
foreach (patientInfo item in FHEDM.rows)
|
2024-12-11 19:48:43 +08:00
|
|
|
|
{
|
2025-04-02 23:01:04 +08:00
|
|
|
|
foreach (projectsInfo projectsInfo in item.projects)
|
2024-12-11 19:48:43 +08:00
|
|
|
|
{
|
2025-04-02 23:01:04 +08:00
|
|
|
|
if (projectsInfo.category == "US")
|
|
|
|
|
{
|
|
|
|
|
HisInfo info = new HisInfo();
|
|
|
|
|
info.jianchaid = item.jianchaid;
|
|
|
|
|
info.name = item.name;
|
|
|
|
|
info.jianchabh = item.jianchabh;
|
|
|
|
|
info.sfz = item.sfz;
|
|
|
|
|
info.birthdate = item.birthdate;
|
|
|
|
|
info.age = item.age;
|
|
|
|
|
info.sex = item.sex;
|
|
|
|
|
info.yiyuanname = item.yiyuanname;
|
|
|
|
|
info.yiyuanid = item.yiyuanid;
|
|
|
|
|
info.yiyuancode = item.yiyuancode;
|
|
|
|
|
info.kaifangsj = item.kaifangsj;
|
|
|
|
|
info.departmentCode = item.departmentCode;
|
|
|
|
|
info.departmentName = item.departmentName;
|
|
|
|
|
info.resDoctorName = item.resDoctorName;
|
|
|
|
|
info.resDoctorCode = item.resDoctorCode;
|
|
|
|
|
info.nation = item.nation;
|
|
|
|
|
info.patientCode = item.patientCode;
|
|
|
|
|
info.visitType = item.visitType;
|
|
|
|
|
info.jianchamingcheng = projectsInfo.jianchamingcheng;
|
|
|
|
|
info.nhbm = projectsInfo.nhbm;
|
|
|
|
|
info.category = projectsInfo.category;
|
|
|
|
|
hisInfos.Add(info);
|
|
|
|
|
}
|
2024-12-11 19:48:43 +08:00
|
|
|
|
|
2025-04-02 23:01:04 +08:00
|
|
|
|
}
|
2024-12-11 19:48:43 +08:00
|
|
|
|
}
|
2025-04-02 23:01:04 +08:00
|
|
|
|
dGVPatient.DataSource = hisInfos;
|
|
|
|
|
rowhisinfo = null;
|
2024-12-11 19:48:43 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
2025-04-02 23:01:04 +08:00
|
|
|
|
catch (Exception e)
|
|
|
|
|
{
|
|
|
|
|
MessageBox.Show("获取接口数据失败");
|
|
|
|
|
}
|
|
|
|
|
|
2024-12-11 19:48:43 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 获取福乐云HIS系统的token
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="username"></param>
|
|
|
|
|
/// <param name="pwd"></param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
public string getHisToken(string url1, string appkey, string appsecret)
|
|
|
|
|
{
|
|
|
|
|
Dictionary<string, object> dic = new Dictionary<string, object>();
|
|
|
|
|
dic.Add("appkey", appkey);
|
|
|
|
|
dic.Add("appsecret", appsecret);
|
|
|
|
|
|
|
|
|
|
string resultV = PostFile3(url1, dic);
|
|
|
|
|
FlyHisTokenMsgModel tm = JsonConvert.DeserializeObject<FlyHisTokenMsgModel>(resultV);
|
|
|
|
|
return tm.data.access_token;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 获取福乐云HIS系统的患者基本信息
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="username"></param>
|
|
|
|
|
/// <param name="pwd"></param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
public FlyHisEcgDataModel GetHisEcgData(string url1, string Yiyuanid, string kaifangsj, string token)
|
|
|
|
|
{
|
|
|
|
|
Dictionary<string, object> dic = new Dictionary<string, object>();
|
|
|
|
|
dic.Add("Yiyuanid", Yiyuanid);
|
|
|
|
|
dic.Add("dateStart", kaifangsj);
|
|
|
|
|
dic.Add("dateEnd", kaifangsj);
|
|
|
|
|
dic.Add("token", token);
|
|
|
|
|
string resultV = PostFile3(url1, dic);
|
|
|
|
|
FlyHisEcgDataModel tm = JsonConvert.DeserializeObject<FlyHisEcgDataModel>(resultV);
|
|
|
|
|
return tm;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// post form-data 参数
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="url"></param>
|
|
|
|
|
/// <param name="items"></param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
public string PostFile3(string url, Dictionary<string, object> items)
|
|
|
|
|
{
|
2025-04-02 23:01:04 +08:00
|
|
|
|
// 忽略证书验证
|
|
|
|
|
ServicePointManager.ServerCertificateValidationCallback += (sender, certificate, chain, sslPolicyErrors) => true;
|
2024-12-11 19:48:43 +08:00
|
|
|
|
string boundary = DateTime.Now.Ticks.ToString("x");
|
|
|
|
|
HttpWebRequest request = null;
|
|
|
|
|
//如果是发送HTTPS请求
|
|
|
|
|
if (url.StartsWith("https", StringComparison.OrdinalIgnoreCase))
|
|
|
|
|
{
|
|
|
|
|
//处理HttpWebRequest访问https有安全证书的问题( 请求被中止: 未能创建 SSL/TLS 安全通道。)
|
|
|
|
|
ServicePointManager.ServerCertificateValidationCallback += (s, cert, chain, sslPolicyErrors) => true;
|
|
|
|
|
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls;
|
|
|
|
|
|
|
|
|
|
//ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(CheckValidationResult);
|
|
|
|
|
request = WebRequest.Create(url) as HttpWebRequest;
|
|
|
|
|
request.ProtocolVersion = HttpVersion.Version10;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
request = WebRequest.Create(url) as HttpWebRequest;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
request.ContentType = "multipart/form-data; boundary=" + boundary;
|
|
|
|
|
request.Method = "POST";
|
|
|
|
|
// request.Headers.Add("Authorization", "Bearer " + token);
|
|
|
|
|
// 最后的结束符
|
|
|
|
|
var endBoundary = Encoding.UTF8.GetBytes("\r\n--" + boundary + "--\r\n");
|
|
|
|
|
|
|
|
|
|
//文件数据
|
|
|
|
|
string fileFormdataTemplate =
|
|
|
|
|
"--" + boundary +
|
|
|
|
|
"\r\nContent-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"" +
|
|
|
|
|
"\r\nContent-Type: application/octet-stream" +
|
|
|
|
|
"\r\n\r\n";
|
|
|
|
|
|
|
|
|
|
//文本数据
|
|
|
|
|
string dataFormdataTemplate =
|
|
|
|
|
"\r\n--" + boundary +
|
|
|
|
|
"\r\nContent-Disposition: form-data; name=\"{0}\"" +
|
|
|
|
|
"\r\n\r\n{1}";
|
|
|
|
|
//FileInfo fi = new FileInfo(filePath);
|
|
|
|
|
//string fileHeader = string.Format(fileFormdataTemplate, "file", fi.Name);
|
|
|
|
|
//var fileBytes = Encoding.UTF8.GetBytes(fileHeader);
|
|
|
|
|
|
|
|
|
|
using (var postStream = new MemoryStream())
|
|
|
|
|
{
|
|
|
|
|
////写入文件格式串
|
|
|
|
|
//postStream.Write(fileBytes, 0, fileBytes.Length);
|
|
|
|
|
|
|
|
|
|
//#region 写入文件流
|
|
|
|
|
//using (var fs = new FileStream(filePath, FileMode.Open, FileAccess.Read))
|
|
|
|
|
//{
|
|
|
|
|
// byte[] buffer = new byte[1024];
|
|
|
|
|
// int bytesRead = 0;
|
|
|
|
|
// while ((bytesRead = fs.Read(buffer, 0, buffer.Length)) != 0)
|
|
|
|
|
// {
|
|
|
|
|
// postStream.Write(buffer, 0, bytesRead);
|
|
|
|
|
// }
|
|
|
|
|
//}
|
|
|
|
|
//#endregion
|
|
|
|
|
|
|
|
|
|
#region 写入其他表单参数
|
|
|
|
|
foreach (KeyValuePair<string, object> key in items)
|
|
|
|
|
{
|
|
|
|
|
var p = string.Format(dataFormdataTemplate, key.Key, key.Value);
|
|
|
|
|
var bp = Encoding.UTF8.GetBytes(p);
|
|
|
|
|
postStream.Write(bp, 0, bp.Length);
|
|
|
|
|
}
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
//写入结束边界
|
|
|
|
|
postStream.Write(endBoundary, 0, endBoundary.Length);
|
|
|
|
|
|
|
|
|
|
#region 写入流
|
|
|
|
|
|
|
|
|
|
request.ContentLength = postStream.Length;
|
|
|
|
|
postStream.Position = 0;
|
|
|
|
|
using (Stream ds = request.GetRequestStream())
|
|
|
|
|
{
|
|
|
|
|
byte[] buffer = new byte[1024];
|
|
|
|
|
int bytesRead = 0;
|
|
|
|
|
while ((bytesRead = postStream.Read(buffer, 0, buffer.Length)) != 0)
|
|
|
|
|
{
|
|
|
|
|
ds.Write(buffer, 0, bytesRead);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region 获取返回值
|
|
|
|
|
|
|
|
|
|
string result = string.Empty;
|
|
|
|
|
using (HttpWebResponse rep = (HttpWebResponse)request.GetResponse())
|
|
|
|
|
{
|
|
|
|
|
using (Stream ds = rep.GetResponseStream())
|
|
|
|
|
{
|
|
|
|
|
using (StreamReader sr = new StreamReader(ds))
|
|
|
|
|
{
|
|
|
|
|
result = sr.ReadToEnd();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region 视频转换
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 转换文件
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="filename"></param>
|
|
|
|
|
/// <returns>转换后文件</returns>
|
|
|
|
|
private string ConvertVideo(string filename)
|
|
|
|
|
{
|
|
|
|
|
Process p = new Process();
|
|
|
|
|
|
|
|
|
|
p.StartInfo.FileName = Application.StartupPath + @"\ffmpeg\" + "ffmpeg";
|
|
|
|
|
|
|
|
|
|
//p.StartInfo.FileName = path + "ffmpeg.exe";
|
|
|
|
|
|
|
|
|
|
p.StartInfo.UseShellExecute = false;
|
|
|
|
|
string srcFileName = "";
|
|
|
|
|
srcFileName = "\"" + filename + "\"";
|
|
|
|
|
string destFileName = Application.StartupPath + "\\" + DateTime.Now.ToString("yyyyMMddhhmmss") + ".mp4";
|
|
|
|
|
//-preset:指定编码的配置。x264编码算法有很多可供配置的参数,
|
|
|
|
|
//不同的参数值会导致编码的速度大相径庭,甚至可能影响质量。
|
|
|
|
|
//为了免去用户了解算法,然后手工配置参数的麻烦。x264提供了一些预设值,
|
|
|
|
|
//而这些预设值可以通过preset指定。这些预设值有包括:
|
|
|
|
|
//ultrafast,superfast,veryfast,faster,fast,medium,slow,slower,veryslow和placebo。
|
|
|
|
|
//ultrafast编码速度最快,但压缩率低,生成的文件更大,placebo则正好相反。x264所取的默认值为medium。
|
|
|
|
|
//需要说明的是,preset主要是影响编码的速度,并不会很大的影响编码出来的结果的质量。
|
|
|
|
|
//-crf:这是最重要的一个选项,用于指定输出视频的质量,取值范围是0-51,默认值为23,数字越小输出视频的质量越高。
|
|
|
|
|
//这个选项会直接影响到输出视频的码率。一般来说,压制480p我会用20左右,压制720p我会用16-18,1080p我没尝试过。
|
|
|
|
|
//个人觉得,一般情况下没有必要低于16。最好的办法是大家可以多尝试几个值,每个都压几分钟,看看最后的输出质量和文件大小,自己再按需选择。
|
|
|
|
|
p.StartInfo.Arguments = "-i " + srcFileName + " -y -vcodec h264 -threads " + 1 + " -crf " + 25 + " " + "\"" + destFileName + "\""; //执行参数
|
|
|
|
|
|
|
|
|
|
p.StartInfo.UseShellExecute = false; ////不使用系统外壳程序启动进程
|
|
|
|
|
p.StartInfo.CreateNoWindow = true; //不显示dos程序窗口
|
|
|
|
|
|
|
|
|
|
p.StartInfo.RedirectStandardInput = true;
|
|
|
|
|
|
|
|
|
|
p.StartInfo.RedirectStandardOutput = true;
|
|
|
|
|
|
|
|
|
|
p.StartInfo.RedirectStandardError = true;//把外部程序错误输出写到StandardError流中
|
|
|
|
|
|
|
|
|
|
p.ErrorDataReceived += new DataReceivedEventHandler(p_ErrorDataReceived);
|
|
|
|
|
|
|
|
|
|
p.OutputDataReceived += new DataReceivedEventHandler(p_OutputDataReceived);
|
|
|
|
|
|
|
|
|
|
p.StartInfo.UseShellExecute = false;
|
|
|
|
|
|
|
|
|
|
p.Start();
|
|
|
|
|
|
|
|
|
|
p.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
|
|
|
|
|
|
|
|
|
|
p.BeginErrorReadLine();//开始异步读取
|
|
|
|
|
|
|
|
|
|
p.WaitForExit();//阻塞等待进程结束
|
|
|
|
|
|
|
|
|
|
p.Close();//关闭进程
|
|
|
|
|
|
|
|
|
|
p.Dispose();//释放资源
|
|
|
|
|
|
|
|
|
|
return destFileName.TrimStart('\\');
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static void p_ErrorDataReceived(object sender, DataReceivedEventArgs e)
|
|
|
|
|
{
|
|
|
|
|
//WriteLog(e.Data);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static void p_OutputDataReceived(object sender, DataReceivedEventArgs e)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
//WriteLog(e.Data);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region 病理相关
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 开启或关闭全局监测
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="sender"></param>
|
|
|
|
|
/// <param name="e"></param>
|
|
|
|
|
private void button2_Click(object sender, EventArgs e)
|
|
|
|
|
{
|
|
|
|
|
var CameraSelect = this.cb_CameraSelect.Text;
|
|
|
|
|
if (string.IsNullOrEmpty(CameraSelect))
|
|
|
|
|
{
|
|
|
|
|
MessageBox.Show("请先选择视频源");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (button2.Text == "开启截图")
|
|
|
|
|
{
|
|
|
|
|
HookStart();
|
|
|
|
|
button2.Text = "关闭截图";
|
|
|
|
|
}
|
|
|
|
|
else if (button2.Text == "关闭截图")
|
|
|
|
|
{
|
|
|
|
|
HookStop();
|
|
|
|
|
button2.Text = "开启截图";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 保存病理截图并且转换成dcm
|
|
|
|
|
/// </summary>
|
|
|
|
|
private void SaveImageDcm()
|
|
|
|
|
{
|
2025-04-11 15:19:17 +08:00
|
|
|
|
Bitmap currentFrame = player.GetCurrentVideoFrame();
|
2024-12-11 19:48:43 +08:00
|
|
|
|
if (currentFrame != null)
|
|
|
|
|
{
|
|
|
|
|
//开启区域截图
|
|
|
|
|
if (checkBox1.Checked)
|
|
|
|
|
{
|
|
|
|
|
int x = int.Parse(txt_x.Text.Trim());
|
|
|
|
|
int y = int.Parse(txt_y.Text.Trim());
|
|
|
|
|
int w = int.Parse(txt_w.Text.Trim());
|
|
|
|
|
int h = int.Parse(txt_h.Text.Trim());
|
|
|
|
|
// 定义你想要裁剪的区域 imgMap
|
|
|
|
|
System.Drawing.Rectangle region = new System.Drawing.Rectangle(x, y, w, h); // 例如,从(10,10)开始,宽100,高100的区域
|
|
|
|
|
|
|
|
|
|
// 裁剪图像区域
|
|
|
|
|
imgMap = currentFrame.Clone(region, currentFrame.PixelFormat);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
imgMap = currentFrame;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool bol = Imaganddcm.ImportImage("123456", "2", "3", "测试", imgMap, _blpath);
|
|
|
|
|
if (bol)
|
|
|
|
|
{
|
|
|
|
|
label5.Text = Imaganddcm.Array.Count.ToString();
|
|
|
|
|
imgMap.Dispose();
|
|
|
|
|
currentFrame.Dispose();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 上传病理dcm并且传递数据
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="sender"></param>
|
|
|
|
|
/// <param name="e"></param>
|
|
|
|
|
private void button3_Click(object sender, EventArgs e)
|
|
|
|
|
{
|
|
|
|
|
//给当前患者创建FTP路径
|
|
|
|
|
FtpHelper.MakeDir("123456");
|
|
|
|
|
//读取当前患者截图文件上传FTP
|
|
|
|
|
string[] filePaths = Directory.GetFiles(_blpath);
|
|
|
|
|
if (!filePaths.Any())
|
|
|
|
|
{
|
|
|
|
|
MessageBox.Show("文件为空");
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
//存放文件访问地址
|
|
|
|
|
ArrayList arrayList = new ArrayList();
|
|
|
|
|
foreach (string filePath in filePaths)
|
|
|
|
|
{
|
|
|
|
|
string fileName = System.IO.Path.GetFileName(filePath);
|
|
|
|
|
string returnStr = FtpHelper.FileUpLoad(filePath, "123456", fileName);//上传文件
|
|
|
|
|
arrayList.Add("123456" + "/" + fileName);
|
|
|
|
|
File.Delete(filePath);
|
|
|
|
|
}
|
|
|
|
|
//调用患者信息接口
|
|
|
|
|
//先获取token
|
|
|
|
|
string msg = Get(_url + "/admin-api/system/jwtToken/getToken?key_public=c4c7dde887706361d8480909043bfdbd");
|
|
|
|
|
if (!string.IsNullOrEmpty(msg))
|
|
|
|
|
{
|
|
|
|
|
MsgInfo person = JsonConvert.DeserializeObject<MsgInfo>(msg);
|
|
|
|
|
if (person != null)
|
|
|
|
|
{
|
|
|
|
|
InsPatientInfo(person.data);
|
|
|
|
|
|
|
|
|
|
InsImageInfo(person.data, arrayList);
|
|
|
|
|
|
|
|
|
|
MessageBox.Show("上传成功");
|
|
|
|
|
Imaganddcm.Array.Clear();
|
|
|
|
|
label5.Text = "0";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 插入患者信息
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
private void InsPatientInfo(string token)
|
|
|
|
|
{
|
|
|
|
|
string strjson = @"[
|
|
|
|
|
{
|
|
|
|
|
""examId"": ""1234567"",
|
|
|
|
|
""pname"": ""病理测试插入患者"",
|
|
|
|
|
""gender"": ""男"",
|
|
|
|
|
""birthday"": ""1727075391000"",
|
|
|
|
|
""deviceType"": ""CSH1"",
|
|
|
|
|
""deviceName"": ""设备测试12"",
|
|
|
|
|
""seDc"": """",
|
|
|
|
|
""examDate"": ""1727075391000"",
|
|
|
|
|
""examItemCode"": ""Z0000000210"",
|
|
|
|
|
""examItemName"": ""病理"",
|
|
|
|
|
""reportstatus"": ""待分析"",
|
|
|
|
|
""applicationDate"": ""1727075391000"",
|
|
|
|
|
""orgId"": ""9f65555c-ce59-4f4c-8f1c-af245ebe5ce6"",
|
|
|
|
|
""orgName"": ""科右前旗康立寿医院"",
|
|
|
|
|
""regId"": ""123456""
|
|
|
|
|
}
|
|
|
|
|
]";
|
|
|
|
|
string msg = Post(_url + "/admin-api/tblist/patientexamlist/addPatientExamInfo", strjson, "AuthToken", token);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 插入影像数据
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="token"></param>
|
|
|
|
|
/// <param name="arrayList"></param>
|
|
|
|
|
private void InsImageInfo(string token, ArrayList arrayList)
|
|
|
|
|
{
|
|
|
|
|
if (arrayList != null)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
int count = 0;
|
|
|
|
|
List<image> images = new List<image>();
|
|
|
|
|
foreach (string str in arrayList)
|
|
|
|
|
{
|
|
|
|
|
count++;
|
|
|
|
|
image imageInfo = new image();
|
|
|
|
|
imageInfo.ImageNumber = count.ToString();
|
|
|
|
|
imageInfo.ObjectFile = str;
|
|
|
|
|
imageInfo.UrlPrefix = _blprefix;
|
|
|
|
|
images.Add(imageInfo);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
Series series = new Series
|
|
|
|
|
{
|
|
|
|
|
SeriesNumb = "1",
|
|
|
|
|
SeriesDesc = "病理",
|
|
|
|
|
Modality = "CSH1",
|
|
|
|
|
image = images
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
//检查项目信息
|
|
|
|
|
Study study = new Study
|
|
|
|
|
{
|
|
|
|
|
StudyDescr = "病理",
|
|
|
|
|
StudyID = "Z0000000033",
|
|
|
|
|
StudyModal = "CSH1",
|
|
|
|
|
Series = new List<Series> { series }
|
|
|
|
|
};
|
|
|
|
|
//患者信息
|
|
|
|
|
Patient patient = new Patient
|
|
|
|
|
{
|
|
|
|
|
PatientID = "123456",
|
|
|
|
|
PatientNam = "病理测试插入患者",
|
|
|
|
|
PatientBir = "511200000000",
|
|
|
|
|
PatientSex = "F",
|
|
|
|
|
OrgId = "9f65555c-ce59-4f4c-8f1c-af245ebe5ce6",
|
|
|
|
|
OrgName = "测试插入1",
|
|
|
|
|
StudyDate = "2024-9-20 13:03:30",
|
|
|
|
|
Studies = new List<Study> { study }
|
|
|
|
|
};
|
|
|
|
|
List<Patient> patientList = new List<Patient>();
|
|
|
|
|
patientList.Add(patient);
|
|
|
|
|
// 将对象转换为JSON字符串
|
|
|
|
|
string json = JsonConvert.SerializeObject(patientList);
|
|
|
|
|
|
|
|
|
|
string msg = Post(_url + "/admin-api/ultrasoniccom/ultrasonic/InsImageInfo", json, "AuthToken", token);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region 钩子相关
|
|
|
|
|
//定义变量
|
|
|
|
|
public delegate int HookProc(int nCode, Int32 wParam, IntPtr lParam);
|
|
|
|
|
static int hKeyboardHook = 0;
|
|
|
|
|
HookProc KeyboardHookProcedure;
|
|
|
|
|
|
|
|
|
|
/*************************
|
|
|
|
|
* 声明API函数
|
|
|
|
|
* ***********************/
|
|
|
|
|
|
|
|
|
|
// 安装钩子 (using System.Runtime.InteropServices;)
|
|
|
|
|
[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
|
|
|
|
|
public static extern int SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hInstance, int threadId);
|
|
|
|
|
// 卸载钩子
|
|
|
|
|
[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
|
|
|
|
|
public static extern bool UnhookWindowsHookEx(int idHook);
|
|
|
|
|
// 继续下一个钩子
|
|
|
|
|
[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
|
|
|
|
|
public static extern int CallNextHookEx(int idHook, int nCode, Int32 wParam, IntPtr lParam);
|
|
|
|
|
// 取得当前线程编号(线程钩子需要用到)
|
|
|
|
|
[DllImport("kernel32.dll")]
|
|
|
|
|
static extern int GetCurrentThreadId();
|
|
|
|
|
|
|
|
|
|
//钩子子程:就是钩子所要做的事情
|
|
|
|
|
private int KeyboardHookProc(int nCode, Int32 wParam, IntPtr lParam)
|
|
|
|
|
{
|
|
|
|
|
if (nCode >= 0)
|
|
|
|
|
{
|
|
|
|
|
/****************
|
|
|
|
|
//线程键盘钩子判断是否按下键
|
|
|
|
|
Keys keyData = (Keys)wParam;
|
|
|
|
|
if(lParam.ToInt32() > 0)
|
|
|
|
|
{
|
|
|
|
|
// 键盘按下
|
|
|
|
|
}
|
|
|
|
|
if(lParam.ToInt32() < 0)
|
|
|
|
|
{
|
|
|
|
|
// 键盘抬起
|
|
|
|
|
}
|
|
|
|
|
****************/
|
|
|
|
|
|
|
|
|
|
/****************
|
|
|
|
|
//全局键盘钩子判断是否按下键
|
|
|
|
|
wParam = = 0x100 // 键盘按下
|
|
|
|
|
wParam = = 0x101 // 键盘抬起
|
|
|
|
|
****************/
|
|
|
|
|
KeyMSG m = (KeyMSG)Marshal.PtrToStructure(lParam, typeof(KeyMSG));//键盘
|
|
|
|
|
Keys key = (Keys)m.vkCode;
|
|
|
|
|
if (wParam == 0x100) // WM_KEYDOWN
|
|
|
|
|
{
|
|
|
|
|
string keyString = key.ToString();
|
|
|
|
|
// MessageBox.Show(keyString);
|
2025-04-02 23:01:04 +08:00
|
|
|
|
//不是病理的 暂时不需要先注释了
|
|
|
|
|
//if (keyString == strkey)
|
|
|
|
|
//{
|
|
|
|
|
// SaveImageDcm();
|
|
|
|
|
//}
|
2024-12-11 19:48:43 +08:00
|
|
|
|
switch (keyString)
|
|
|
|
|
{
|
|
|
|
|
case "F6":
|
|
|
|
|
if (!IsStartVideo)
|
|
|
|
|
{
|
|
|
|
|
btn_StartVideo_Click(null, null);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case "F7":
|
|
|
|
|
btn_PauseVideo_Click(null, null);
|
|
|
|
|
break;
|
|
|
|
|
case "F8":
|
|
|
|
|
if (IsStartVideo)
|
|
|
|
|
{
|
|
|
|
|
btn_EndVideo_Click(null, null);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case "F9":
|
|
|
|
|
btn_Capture_Click(null, null);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
// MessageBox.Show("Key down: " + key.ToString());
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
else if (wParam == 0x101) // WM_KEYUP
|
|
|
|
|
{
|
|
|
|
|
// MessageBox.Show("Key up: " + key.ToString());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// return CallNextHookEx(hKeyboardHook, nCode, wParam, lParam);
|
|
|
|
|
return 0;//如果返回1,则结束消息,这个消息到此为止,不再传递。如果返回0或调用CallNextHookEx函数则消息出了这个钩子继续往下传递,也就是传给消息真正的接受者
|
|
|
|
|
}
|
|
|
|
|
return CallNextHookEx(hKeyboardHook, nCode, wParam, lParam);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//键盘结构
|
|
|
|
|
public struct KeyMSG
|
|
|
|
|
{
|
|
|
|
|
public int vkCode; //键值
|
|
|
|
|
public int scanCode;
|
|
|
|
|
public int flags;
|
|
|
|
|
public int time;
|
|
|
|
|
public int dwExtraInfo;
|
|
|
|
|
}
|
|
|
|
|
// 安装钩子
|
|
|
|
|
public void HookStart()
|
|
|
|
|
{
|
|
|
|
|
if (hKeyboardHook == 0)
|
|
|
|
|
{
|
|
|
|
|
// 创建HookProc实例
|
|
|
|
|
KeyboardHookProcedure = new HookProc(KeyboardHookProc);
|
|
|
|
|
// 设置线程钩子
|
|
|
|
|
|
|
|
|
|
hKeyboardHook = SetWindowsHookEx(13, KeyboardHookProcedure, Marshal.GetHINSTANCE(Assembly.GetExecutingAssembly().GetModules()[0]), 0);
|
|
|
|
|
|
|
|
|
|
//************************************
|
|
|
|
|
//键盘线程钩子
|
|
|
|
|
//SetWindowsHookEx( 2,KeyboardHookProcedure, IntPtr.Zero, GetCurrentThreadId());
|
|
|
|
|
//键盘全局钩子,需要引用空间(using System.Reflection;)
|
|
|
|
|
//SetWindowsHookEx( 13,KeyboardHookProcedure,Marshal.GetHINSTANCE(Assembly.GetExecutingAssembly().GetModules()[0]),0);
|
|
|
|
|
//
|
|
|
|
|
//关于SetWindowsHookEx (int idHook, HookProc lpfn, IntPtr hInstance, int threadId)函数将钩子加入到钩子链表中,说明一下四个参数:
|
|
|
|
|
//idHook 钩子类型,即确定钩子监听何种消息,上面的代码中设为2,即监听键盘消息并且是线程钩子,如果是全局钩子监听键盘消息应设为13,
|
|
|
|
|
//线程钩子监听鼠标消息设为7,全局钩子监听鼠标消息设为14。
|
|
|
|
|
//
|
|
|
|
|
//lpfn 钩子子程的地址指针。如果dwThreadId参数为0 或是一个由别的进程创建的线程的标识,lpfn必须指向DLL中的钩子子程。 除此以外,lpfn可
|
|
|
|
|
//以指向当前进程的一段钩子子程代码。钩子函数的入口地址,当钩子钩到任何消息后便调用这个函数。
|
|
|
|
|
//
|
|
|
|
|
//hInstance应用程序实例的句柄。标识包含lpfn所指的子程的DLL。如果threadId 标识当前进程创建的一个线程,而且子程代码位于当前
|
|
|
|
|
//进程,hInstance必须为NULL。可以很简单的设定其为本应用程序的实例句柄。
|
|
|
|
|
//
|
|
|
|
|
//threadedId 与安装的钩子子程相关联的线程的标识符。如果为0,钩子子程与所有的线程关联,即为全局钩子。
|
|
|
|
|
//************************************
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 如果设置钩子失败
|
|
|
|
|
if (hKeyboardHook == 0)
|
|
|
|
|
{
|
|
|
|
|
HookStop();
|
|
|
|
|
throw new Exception("SetWindowsHookEx failed.");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// 卸载钩子
|
|
|
|
|
public void HookStop()
|
|
|
|
|
{
|
|
|
|
|
bool retKeyboard = true;
|
|
|
|
|
if (hKeyboardHook != 0)
|
|
|
|
|
{
|
|
|
|
|
retKeyboard = UnhookWindowsHookEx(hKeyboardHook);
|
|
|
|
|
hKeyboardHook = 0;
|
|
|
|
|
}
|
|
|
|
|
if (!(retKeyboard))
|
|
|
|
|
throw new Exception("UnhookWindowsHookEx failed.");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 是否开启区域截图
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="sender"></param>
|
|
|
|
|
/// <param name="e"></param>
|
|
|
|
|
private void checkBox1_Click(object sender, EventArgs e)
|
|
|
|
|
{
|
|
|
|
|
if (!checkBox1.Checked)
|
|
|
|
|
{
|
|
|
|
|
txt_x.Enabled = false;
|
|
|
|
|
txt_y.Enabled = false;
|
|
|
|
|
txt_w.Enabled = false;
|
|
|
|
|
txt_h.Enabled = false;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
txt_x.Enabled = true;
|
|
|
|
|
txt_y.Enabled = true;
|
|
|
|
|
txt_w.Enabled = true;
|
|
|
|
|
txt_h.Enabled = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 双击患者列 选中患者
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="sender"></param>
|
|
|
|
|
/// <param name="e"></param>
|
|
|
|
|
private void dGVPatient_CellDoubleClick(object sender, DataGridViewCellEventArgs e)
|
|
|
|
|
{
|
|
|
|
|
// 检查是否双击了整行
|
|
|
|
|
if (e.RowIndex >= 0) // 确保是行内的单元格被双击
|
|
|
|
|
{
|
|
|
|
|
// 获取当前行的所有单元格
|
|
|
|
|
DataGridViewRow row = dGVPatient.Rows[e.RowIndex];
|
|
|
|
|
rowhisinfo = (HisInfo)row.DataBoundItem;
|
|
|
|
|
label3.Text = "双击选择患者" + " 当前患者:" + rowhisinfo.name;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 患者数据上传
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="sender"></param>
|
|
|
|
|
/// <param name="e"></param>
|
|
|
|
|
private void button4_Click(object sender, EventArgs e)
|
|
|
|
|
{
|
|
|
|
|
if (rowhisinfo == null)
|
|
|
|
|
{
|
|
|
|
|
MessageBox.Show("请选择患者");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (imagearray.Count <= 0 && string.IsNullOrEmpty(videoName))
|
|
|
|
|
{
|
|
|
|
|
MessageBox.Show("暂无需要上传的患者和文件");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
this.backgroundWorker1.RunWorkerAsync(); // 运行 backgroundWorker 组件
|
|
|
|
|
|
|
|
|
|
ProcessForm form = new ProcessForm(this.backgroundWorker1);// 显示进度条窗体
|
|
|
|
|
form.ShowDialog(this);
|
|
|
|
|
form.Close();
|
|
|
|
|
MessageBox.Show("上传成功");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#region 线程执行
|
|
|
|
|
|
|
|
|
|
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
|
|
|
|
|
{
|
|
|
|
|
if (e.Error != null)
|
|
|
|
|
{
|
|
|
|
|
MessageBox.Show(e.Error.Message);
|
|
|
|
|
}
|
|
|
|
|
else if (e.Cancelled)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//你可以在这个方法内,实现你的调用,方法等。
|
|
|
|
|
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
|
|
|
|
|
{
|
|
|
|
|
BackgroundWorker worker = sender as BackgroundWorker;
|
|
|
|
|
|
|
|
|
|
//上传图片
|
|
|
|
|
#region 上传图片
|
|
|
|
|
|
|
|
|
|
string returnStr = string.Empty;
|
|
|
|
|
foreach (var item in imagearray)
|
|
|
|
|
{
|
|
|
|
|
string fileName = System.IO.Path.GetFileName(item.ToString());
|
|
|
|
|
if (_model == "0")
|
|
|
|
|
{
|
|
|
|
|
returnStr = SaveFile(item.ToString(), ConfigurationManager.AppSettings["filepath"] + "\\" + rowhisinfo.jianchaid, fileName.Split('.')[0], "jpg");
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
returnStr = FtpHelper.FileUpLoad(item.ToString(), ConfigurationManager.AppSettings["path1"], fileName);//上传文件
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!string.IsNullOrEmpty(returnStr) && returnStr == "上传成功")
|
|
|
|
|
{
|
|
|
|
|
//上传成功 清除文件
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
UploadFileUrl(fileName, ".jpg");
|
|
|
|
|
// 删除文件
|
|
|
|
|
File.Delete(item.ToString());
|
|
|
|
|
worker.ReportProgress(10);
|
|
|
|
|
}
|
|
|
|
|
catch (IOException ex)
|
|
|
|
|
{
|
|
|
|
|
MessageBox.Show("删除文件时出错: " + ex.Message);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
catch (UnauthorizedAccessException ex)
|
|
|
|
|
{
|
|
|
|
|
MessageBox.Show("没有权限删除文件: " + ex.Message);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region 上传视频
|
|
|
|
|
if (!string.IsNullOrEmpty(videoName))
|
|
|
|
|
{
|
|
|
|
|
bool fileExists = File.Exists(videoName);
|
|
|
|
|
if (fileExists)
|
|
|
|
|
{
|
|
|
|
|
string newfilename = ConvertVideo(videoName);
|
|
|
|
|
if (_model == "0")
|
|
|
|
|
{
|
|
|
|
|
returnStr = SaveFile(newfilename, ConfigurationManager.AppSettings["filepath"] + "\\" + rowhisinfo.jianchaid, fileName, "mp4");
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
returnStr = FtpHelper.FileUpLoad(newfilename, ConfigurationManager.AppSettings["path1"], fileName + ".mp4");//上传文件
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!string.IsNullOrEmpty(returnStr) && returnStr == "上传成功")
|
|
|
|
|
{
|
|
|
|
|
//上传成功 清除文件
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
UploadFileUrl(fileName + ".mp4", ".mp4");
|
|
|
|
|
// 删除文件
|
|
|
|
|
File.Delete(videoName);
|
|
|
|
|
// 删除文件
|
|
|
|
|
File.Delete(newfilename);
|
|
|
|
|
worker.ReportProgress(10);
|
|
|
|
|
}
|
|
|
|
|
catch (IOException ex)
|
|
|
|
|
{
|
|
|
|
|
MessageBox.Show("删除文件时出错: " + ex.Message);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
catch (UnauthorizedAccessException ex)
|
|
|
|
|
{
|
|
|
|
|
MessageBox.Show("没有权限删除文件: " + ex.Message);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
this.Invoke(new Action(() =>
|
|
|
|
|
{
|
|
|
|
|
tick_num = 0;
|
|
|
|
|
lab_Time.Text = "00:00:00";
|
|
|
|
|
}));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region 插入患者
|
|
|
|
|
worker.ReportProgress(70);
|
|
|
|
|
string token = Get(_url + "/admin-api/system/jwtToken/getToken?key_public=c4c7dde887706361d8480909043bfdbd");
|
|
|
|
|
if (!string.IsNullOrEmpty(token))
|
|
|
|
|
{
|
|
|
|
|
MsgInfo person = JsonConvert.DeserializeObject<MsgInfo>(token);
|
|
|
|
|
List<ExamRecord> Record = new List<ExamRecord>();
|
|
|
|
|
|
|
|
|
|
ExamRecord examRecord = new ExamRecord();
|
2025-04-02 23:01:04 +08:00
|
|
|
|
examRecord.examId = _isInspect == "1" ? rowhisinfo.jianchabh : rowhisinfo.jianchabh + "_" + GetRandomNumber(1, 100);
|
|
|
|
|
examRecord.sfz = rowhisinfo.sfz;
|
2024-12-11 19:48:43 +08:00
|
|
|
|
examRecord.pname = rowhisinfo.name;
|
|
|
|
|
examRecord.gender = rowhisinfo.sex;
|
2025-04-02 23:01:04 +08:00
|
|
|
|
examRecord.birthday = GetTimestampFromBirthdate(rowhisinfo.birthdate).ToString();
|
2024-12-11 19:48:43 +08:00
|
|
|
|
examRecord.deviceType = "US";//rowhisinfo.category
|
|
|
|
|
examRecord.deviceName = "彩超";
|
|
|
|
|
examRecord.seDc = "1/1";
|
|
|
|
|
examRecord.examDate = GetTimestampFromdate(rowhisinfo.kaifangsj).ToString();
|
|
|
|
|
examRecord.examItemName = rowhisinfo.jianchamingcheng;
|
|
|
|
|
examRecord.examItemCode = rowhisinfo.nhbm;
|
|
|
|
|
examRecord.reportstatus = "待分析";
|
|
|
|
|
examRecord.applicationDate = GetTimestampFromdate(rowhisinfo.kaifangsj).ToString();
|
|
|
|
|
examRecord.orgId = rowhisinfo.yiyuancode;//9f65555c-ce59-4f4c-8f1c-af245ebe5ce6 rowhisinfo.yiyuanid
|
|
|
|
|
examRecord.orgName = rowhisinfo.yiyuanname;
|
|
|
|
|
examRecord.regId = rowhisinfo.jianchaid;
|
|
|
|
|
Record.Add(examRecord);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var json = JsonConvert.SerializeObject(Record);
|
|
|
|
|
string msg = Post(_url + "/admin-api/tblist/patientexamlist/addPatientExamInfo", json, "AuthToken", person.data);
|
|
|
|
|
worker.ReportProgress(100);
|
|
|
|
|
this.Invoke(new Action(() =>
|
|
|
|
|
{
|
|
|
|
|
//截图数量置为0
|
|
|
|
|
label1.Text = "0";
|
|
|
|
|
//选择患者置为空
|
|
|
|
|
rowhisinfo = null;
|
|
|
|
|
imagearray.Clear();
|
|
|
|
|
videoName = string.Empty;
|
|
|
|
|
label3.Text = "双击选择患者";
|
|
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private void gb_ButtonBox_Enter(object sender, EventArgs e)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static int GetRandomNumber(int minValue, int maxValue)
|
|
|
|
|
{
|
|
|
|
|
Random random = new Random(); // 实例化Random类
|
|
|
|
|
return random.Next(minValue, maxValue); // 返回一个随机整数
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 获取当前时间的Unix时间戳(毫秒)
|
|
|
|
|
public static string GetCurrentTimestamp()
|
|
|
|
|
{
|
|
|
|
|
// DateTime.UtcNow 获取当前UTC时间
|
|
|
|
|
// Subtract 方法减去1970年1月1日的时间
|
|
|
|
|
// TotalMilliseconds 获取总毫秒数
|
|
|
|
|
return DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1)).TotalMilliseconds.ToString();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 将指定的出生日期转换为Unix时间戳(毫秒)
|
|
|
|
|
public static long GetTimestampFromBirthdate(string birthdate)
|
|
|
|
|
{
|
2025-04-02 23:01:04 +08:00
|
|
|
|
|
2024-12-11 19:48:43 +08:00
|
|
|
|
// 尝试解析日期字符串
|
|
|
|
|
DateTime birthDateTime;
|
|
|
|
|
if (DateTime.TryParseExact(birthdate, "yyyy-MM-dd", CultureInfo.InvariantCulture, DateTimeStyles.None, out birthDateTime))
|
|
|
|
|
{
|
|
|
|
|
// 将本地时间转换为UTC时间
|
|
|
|
|
DateTime birthDateTimeUtc = birthDateTime.ToUniversalTime();
|
|
|
|
|
// 计算时间戳
|
|
|
|
|
TimeSpan elapsedTime = birthDateTimeUtc - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
|
|
|
|
|
return (long)elapsedTime.TotalMilliseconds;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// 如果日期格式不正确,抛出异常
|
|
|
|
|
throw new ArgumentException("无效的日期格式。正确的格式应该是yyyy-MM-dd。");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static long GetTimestampFromdate(string birthdate)
|
2025-04-02 23:01:04 +08:00
|
|
|
|
{
|
|
|
|
|
|
2024-12-11 19:48:43 +08:00
|
|
|
|
// 尝试解析日期字符串
|
|
|
|
|
DateTime birthDateTime;
|
|
|
|
|
if (DateTime.TryParseExact(birthdate, "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture, DateTimeStyles.None, out birthDateTime))
|
|
|
|
|
{
|
2025-04-02 23:01:04 +08:00
|
|
|
|
|
2024-12-11 19:48:43 +08:00
|
|
|
|
// 将本地时间转换为UTC时间
|
|
|
|
|
DateTime birthDateTimeUtc = birthDateTime.ToUniversalTime();
|
|
|
|
|
// 计算时间戳
|
2025-04-02 23:01:04 +08:00
|
|
|
|
return (long)birthDateTimeUtc.Subtract(new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalMilliseconds;
|
2024-12-11 19:48:43 +08:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// 如果日期格式不正确,抛出异常或返回0
|
|
|
|
|
throw new ArgumentException("无效的日期格式。正确的格式应该是yyyy-MM-dd。");
|
|
|
|
|
// 或者返回0,取决于你希望如何处理错误
|
|
|
|
|
// return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 刷新患者
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="sender"></param>
|
|
|
|
|
/// <param name="e"></param>
|
|
|
|
|
private void button1_Click_1(object sender, EventArgs e)
|
|
|
|
|
{
|
|
|
|
|
GetHisInfo();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void button5_Click(object sender, EventArgs e)
|
|
|
|
|
{
|
|
|
|
|
// 创建一个OpenFileDialog实例
|
|
|
|
|
OpenFileDialog openFileDialog = new OpenFileDialog();
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
// 设置OpenFileDialog的属性
|
|
|
|
|
openFileDialog.InitialDirectory = "C:\\"; // 初始目录
|
|
|
|
|
openFileDialog.Title = "请选择一个图像文件"; // 对话框标题
|
|
|
|
|
openFileDialog.Filter = "图像文件 (*.jpg;*.jpeg;*.png;*.bmp)|*.jpg;*.jpeg;*.png;*.bmp"; // 文件过滤器
|
|
|
|
|
|
|
|
|
|
// 显示OpenFileDialog
|
|
|
|
|
if (openFileDialog.ShowDialog() == DialogResult.OK)
|
|
|
|
|
{
|
|
|
|
|
// 获取选中的文件路径
|
|
|
|
|
string selectedFilePath = openFileDialog.FileName;
|
|
|
|
|
using (FileStream fs = new FileStream(selectedFilePath, FileMode.Open, FileAccess.Read))
|
|
|
|
|
{
|
|
|
|
|
using (Bitmap bitmap = new Bitmap(fs))
|
|
|
|
|
{
|
|
|
|
|
bool bol = Imaganddcm.ImportImage("M20241025", "202410253", "202410253", "树艳", bitmap, _blpath);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
// 异常处理
|
|
|
|
|
Console.WriteLine("发生异常:" + ex.Message);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#region 调用接口上传文件
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 调用接口上传文件
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="imageBase">文件所在的路径</param>
|
|
|
|
|
/// <param name="folderPath">文件保存的文件夹路径</param>
|
|
|
|
|
/// <param name="fileName">文件名(不包含扩展名)</param>
|
|
|
|
|
/// <param name="extension">文件扩展名(例如 "png", "jpg", "txt")</param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
private string SaveFile(string imageBase, string folderPath, string fileName, string extension)
|
|
|
|
|
{
|
|
|
|
|
string base64String = ConvertFileToBase64(imageBase);
|
|
|
|
|
if (string.IsNullOrEmpty(base64String))
|
|
|
|
|
{
|
|
|
|
|
return "文件为空";
|
|
|
|
|
}
|
|
|
|
|
SaveFile saveFile = new SaveFile();
|
|
|
|
|
saveFile.imagebase = base64String;
|
|
|
|
|
saveFile.folderPath = folderPath;
|
|
|
|
|
saveFile.fileName = fileName;
|
|
|
|
|
saveFile.extension = extension;
|
|
|
|
|
|
|
|
|
|
var json = JsonConvert.SerializeObject(saveFile);
|
|
|
|
|
string msg = Post(_url + "/admin-api/ultrasoniccom/ultrasonic/SaveFileBase64", json);
|
|
|
|
|
return msg;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 文件转换成base64
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="filePath"></param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
/// <exception cref="FileNotFoundException"></exception>
|
|
|
|
|
private string ConvertFileToBase64(string filePath)
|
|
|
|
|
{
|
|
|
|
|
string base64String = string.Empty;
|
|
|
|
|
// 确保文件存在
|
|
|
|
|
if (File.Exists(filePath))
|
|
|
|
|
{
|
|
|
|
|
// 读取文件内容到字节数组中
|
|
|
|
|
byte[] fileBytes = File.ReadAllBytes(filePath);
|
|
|
|
|
|
|
|
|
|
// 将字节数组转换为Base64字符串
|
|
|
|
|
base64String = Convert.ToBase64String(fileBytes);
|
|
|
|
|
}
|
|
|
|
|
return base64String;
|
|
|
|
|
}
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 添加患者
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="sender"></param>
|
|
|
|
|
/// <param name="e"></param>
|
|
|
|
|
private void button6_Click(object sender, EventArgs e)
|
|
|
|
|
{
|
|
|
|
|
InfoForm infoForm = new InfoForm();
|
|
|
|
|
if (infoForm.ShowDialog() == DialogResult.OK)
|
|
|
|
|
{
|
|
|
|
|
//先赋空再绑定
|
2025-04-02 23:01:04 +08:00
|
|
|
|
dGVPatient.DataSource = null;
|
2024-12-11 19:48:43 +08:00
|
|
|
|
hisInfos.Add(infoForm.info);
|
|
|
|
|
dGVPatient.DataSource = hisInfos;
|
|
|
|
|
rowhisinfo = null;
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-04-02 23:01:04 +08:00
|
|
|
|
|
|
|
|
|
private void textBox1_KeyDown(object sender, KeyEventArgs e)
|
|
|
|
|
{
|
|
|
|
|
if (e.KeyCode == Keys.Enter)
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
if (string.IsNullOrEmpty(textBox1.Text.Trim()))
|
|
|
|
|
{
|
|
|
|
|
MessageBox.Show("请输入体检编号");
|
|
|
|
|
textBox1.Text = "";
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
string result = Get(_InspectUrl + "/admin-api/inspect/patient/getUSPatientInfo?medicalSn=" + textBox1.Text.Trim() + "");
|
|
|
|
|
if (!string.IsNullOrEmpty(result))
|
|
|
|
|
{
|
|
|
|
|
RootObject msgInfo = JsonConvert.DeserializeObject<RootObject>(result);
|
|
|
|
|
if (msgInfo != null)
|
|
|
|
|
{
|
|
|
|
|
if (msgInfo.data != null)
|
|
|
|
|
{
|
|
|
|
|
HisInfo info = new HisInfo();
|
|
|
|
|
info.jianchaid = msgInfo.data.jianchaid;
|
|
|
|
|
info.name = msgInfo.data.name;
|
|
|
|
|
info.jianchabh = msgInfo.data.jianchabh;
|
|
|
|
|
info.birthdate = msgInfo.data.birthdate;
|
|
|
|
|
info.age = string.IsNullOrEmpty(msgInfo.data.age) ? 0 : int.Parse(msgInfo.data.age);
|
|
|
|
|
info.sex = msgInfo.data.sex;
|
|
|
|
|
info.yiyuanname = ConfigurationManager.AppSettings["yymc"];
|
|
|
|
|
info.yiyuancode = ConfigurationManager.AppSettings["yycode"];
|
|
|
|
|
info.kaifangsj = msgInfo.data.kaifangsj;
|
|
|
|
|
info.jianchamingcheng = msgInfo.data.examItemName;
|
|
|
|
|
info.nhbm = msgInfo.data.examItemCode;
|
|
|
|
|
|
|
|
|
|
//先赋空再绑定
|
|
|
|
|
dGVPatient.DataSource = null;
|
|
|
|
|
hisInfos.Add(info);
|
|
|
|
|
dGVPatient.DataSource = hisInfos;
|
|
|
|
|
textBox1.Text = "";
|
|
|
|
|
rowhisinfo = null;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
MessageBox.Show("未找到该患者信息");
|
|
|
|
|
textBox1.Text = "";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
MessageBox.Show("未找到该患者信息");
|
|
|
|
|
textBox1.Text = "";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
MessageBox.Show(ex.Message);
|
|
|
|
|
textBox1.Text = "";
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-04-11 15:19:17 +08:00
|
|
|
|
|
|
|
|
|
private void button7_Click(object sender, EventArgs e)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#region 新的方式内容
|
|
|
|
|
//private void StartCamera()
|
|
|
|
|
//{
|
|
|
|
|
|
|
|
|
|
// DsDevice[] devices = DsDevice.GetDevicesOfCat(FilterCategory.VideoInputDevice);
|
|
|
|
|
|
|
|
|
|
// if (devices.Length == 0)
|
|
|
|
|
// {
|
|
|
|
|
// MessageBox.Show("无相机连接!");
|
|
|
|
|
// return;
|
|
|
|
|
// }
|
|
|
|
|
// else
|
|
|
|
|
// {
|
|
|
|
|
|
|
|
|
|
// CaptureVideo((DsDevice)comboBox1.SelectedItem);
|
|
|
|
|
// }
|
|
|
|
|
//}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public void CaptureVideo(DsDevice device)
|
|
|
|
|
{
|
|
|
|
|
pictureBox1.Image = null;
|
|
|
|
|
int hr = 0;
|
|
|
|
|
IBaseFilter sourceFilter = null;
|
|
|
|
|
ISampleGrabber sampleGrabber = null;
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
GetInterfaces();
|
|
|
|
|
hr = this.captureGraphBuilder.SetFiltergraph(this.graphBuilder);
|
|
|
|
|
DsError.ThrowExceptionForHR(hr);
|
|
|
|
|
sourceFilter = SelectCaptureDevice(device);
|
|
|
|
|
hr = this.graphBuilder.AddFilter(sourceFilter, "Video Capture");
|
|
|
|
|
DsError.ThrowExceptionForHR(hr);
|
|
|
|
|
sampleGrabber = new SampleGrabber() as ISampleGrabber;
|
|
|
|
|
ConfigureSampleGrabber(sampleGrabber);
|
|
|
|
|
hr = this.graphBuilder.AddFilter(sampleGrabber as IBaseFilter, "Frame Callback");
|
|
|
|
|
DsError.ThrowExceptionForHR(hr);
|
|
|
|
|
SetConfigParams(this.captureGraphBuilder, sourceFilter, _pFPS, _pWidth, _pHeight);
|
|
|
|
|
hr = this.captureGraphBuilder.RenderStream(PinCategory.Preview, MediaType.Video, sourceFilter, (sampleGrabber as IBaseFilter), null);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
DsError.ThrowExceptionForHR(hr);
|
|
|
|
|
|
|
|
|
|
SaveSizeInfo(sampleGrabber);
|
|
|
|
|
SetupVideoWindow();
|
|
|
|
|
|
|
|
|
|
rot = new DsROTEntry(this.graphBuilder);
|
|
|
|
|
|
|
|
|
|
hr = this.mediaControl.Run();
|
|
|
|
|
DsError.ThrowExceptionForHR(hr);
|
|
|
|
|
}
|
|
|
|
|
catch
|
|
|
|
|
{
|
|
|
|
|
MessageBox.Show("error!");
|
|
|
|
|
}
|
|
|
|
|
finally
|
|
|
|
|
{
|
|
|
|
|
if (sourceFilter != null)
|
|
|
|
|
{
|
|
|
|
|
Marshal.ReleaseComObject(sourceFilter);
|
|
|
|
|
sourceFilter = null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (sampleGrabber != null)
|
|
|
|
|
{
|
|
|
|
|
Marshal.ReleaseComObject(sampleGrabber);
|
|
|
|
|
sampleGrabber = null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void CaptureVideo()
|
|
|
|
|
{
|
|
|
|
|
pictureBox1.Image = null;
|
|
|
|
|
int hr = 0;
|
|
|
|
|
IBaseFilter sourceFilter = null;
|
|
|
|
|
ISampleGrabber sampleGrabber = null;
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
// Get DirectShow interfaces
|
|
|
|
|
GetInterfaces();
|
|
|
|
|
|
|
|
|
|
// Attach the filter graph to the capture graph
|
|
|
|
|
hr = this.captureGraphBuilder.SetFiltergraph(this.graphBuilder);
|
|
|
|
|
DsError.ThrowExceptionForHR(hr);
|
|
|
|
|
|
|
|
|
|
// Use the system device enumerator and class enumerator to find
|
|
|
|
|
// a video capture/preview device, such as a desktop USB video camera.
|
|
|
|
|
sourceFilter = FindCaptureDevice();
|
|
|
|
|
// Add Capture filter to graph.
|
|
|
|
|
hr = this.graphBuilder.AddFilter(sourceFilter, "Video Capture");
|
|
|
|
|
DsError.ThrowExceptionForHR(hr);
|
|
|
|
|
|
|
|
|
|
// Initialize SampleGrabber.
|
|
|
|
|
sampleGrabber = new SampleGrabber() as ISampleGrabber;
|
|
|
|
|
// Configure SampleGrabber. Add preview callback.
|
|
|
|
|
ConfigureSampleGrabber(sampleGrabber);
|
|
|
|
|
|
|
|
|
|
// Add SampleGrabber to graph.
|
|
|
|
|
hr = this.graphBuilder.AddFilter(sampleGrabber as IBaseFilter, "Frame Callback");
|
|
|
|
|
DsError.ThrowExceptionForHR(hr);
|
|
|
|
|
|
|
|
|
|
// Configure preview settings.
|
|
|
|
|
SetConfigParams(this.captureGraphBuilder, sourceFilter, _pFPS, _pWidth, _pHeight);
|
|
|
|
|
|
|
|
|
|
// Render the preview
|
|
|
|
|
hr = this.captureGraphBuilder.RenderStream(PinCategory.Preview, MediaType.Video, sourceFilter, (sampleGrabber as IBaseFilter), null);
|
|
|
|
|
DsError.ThrowExceptionForHR(hr);
|
|
|
|
|
|
|
|
|
|
SaveSizeInfo(sampleGrabber);
|
|
|
|
|
|
|
|
|
|
// Set video window style and position
|
|
|
|
|
SetupVideoWindow();
|
|
|
|
|
|
|
|
|
|
// Add our graph to the running object table, which will allow
|
|
|
|
|
// the GraphEdit application to "spy" on our graph
|
|
|
|
|
rot = new DsROTEntry(this.graphBuilder);
|
|
|
|
|
|
|
|
|
|
// Start previewing video data
|
|
|
|
|
hr = this.mediaControl.Run();
|
|
|
|
|
DsError.ThrowExceptionForHR(hr);
|
|
|
|
|
}
|
|
|
|
|
catch
|
|
|
|
|
{
|
|
|
|
|
MessageBox.Show("error!");
|
|
|
|
|
}
|
|
|
|
|
finally
|
|
|
|
|
{
|
|
|
|
|
if (sourceFilter != null)
|
|
|
|
|
{
|
|
|
|
|
Marshal.ReleaseComObject(sourceFilter);
|
|
|
|
|
sourceFilter = null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (sampleGrabber != null)
|
|
|
|
|
{
|
|
|
|
|
Marshal.ReleaseComObject(sampleGrabber);
|
|
|
|
|
sampleGrabber = null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public IBaseFilter SelectCaptureDevice(DsDevice device)
|
|
|
|
|
{
|
|
|
|
|
object source = null;
|
|
|
|
|
Guid iid = typeof(IBaseFilter).GUID;
|
|
|
|
|
device.Mon.BindToObject(null, null, ref iid, out source);
|
|
|
|
|
return (IBaseFilter)source;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public IBaseFilter FindCaptureDevice()
|
|
|
|
|
{
|
|
|
|
|
int hr = 0;
|
|
|
|
|
#if USING_NET11
|
|
|
|
|
UCOMIEnumMoniker classEnum = null;
|
|
|
|
|
UCOMIMoniker[] moniker = new UCOMIMoniker[1];
|
|
|
|
|
#else
|
|
|
|
|
IEnumMoniker classEnum = null;
|
|
|
|
|
IMoniker[] moniker = new IMoniker[1];
|
|
|
|
|
#endif
|
|
|
|
|
object source = null;
|
|
|
|
|
|
|
|
|
|
// Create the system device enumerator
|
|
|
|
|
ICreateDevEnum devEnum = (ICreateDevEnum)new CreateDevEnum();
|
|
|
|
|
|
|
|
|
|
// Create an enumerator for the video capture devices
|
|
|
|
|
hr = devEnum.CreateClassEnumerator(FilterCategory.VideoInputDevice, out classEnum, 0);
|
|
|
|
|
DsError.ThrowExceptionForHR(hr);
|
|
|
|
|
|
|
|
|
|
// The device enumerator is no more needed
|
|
|
|
|
Marshal.ReleaseComObject(devEnum);
|
|
|
|
|
|
|
|
|
|
// If there are no enumerators for the requested type, then
|
|
|
|
|
// CreateClassEnumerator will succeed, but classEnum will be NULL.
|
|
|
|
|
if (classEnum == null)
|
|
|
|
|
{
|
|
|
|
|
throw new ApplicationException("No video capture device was detected.\r\n\r\n" +
|
|
|
|
|
"This sample requires a video capture device, such as a USB WebCam,\r\n" +
|
|
|
|
|
"to be installed and working properly. The sample will now close.");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Use the first video capture device on the device list.
|
|
|
|
|
// Note that if the Next() call succeeds but there are no monikers,
|
|
|
|
|
// it will return 1 (S_FALSE) (which is not a failure). Therefore, we
|
|
|
|
|
// check that the return code is 0 (S_OK).
|
|
|
|
|
#if USING_NET11
|
|
|
|
|
int i;
|
|
|
|
|
if (classEnum.Next (moniker.Length, moniker, IntPtr.Zero) == 0)
|
|
|
|
|
#else
|
|
|
|
|
if (classEnum.Next(moniker.Length, moniker, IntPtr.Zero) == 0)
|
|
|
|
|
#endif
|
|
|
|
|
{
|
|
|
|
|
// Bind Moniker to a filter object
|
|
|
|
|
Guid iid = typeof(IBaseFilter).GUID;
|
|
|
|
|
moniker[0].BindToObject(null, null, ref iid, out source);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
throw new ApplicationException("Unable to access video capture device!");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Release COM objects
|
|
|
|
|
Marshal.ReleaseComObject(moniker[0]);
|
|
|
|
|
Marshal.ReleaseComObject(classEnum);
|
|
|
|
|
|
|
|
|
|
// An exception is thrown if cast fail
|
|
|
|
|
return (IBaseFilter)source;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void GetInterfaces()
|
|
|
|
|
{
|
|
|
|
|
int hr = 0;
|
|
|
|
|
|
|
|
|
|
// An exception is thrown if cast fail
|
|
|
|
|
this.graphBuilder = (IFilterGraph2)new FilterGraph();
|
|
|
|
|
this.captureGraphBuilder = (ICaptureGraphBuilder2)new CaptureGraphBuilder2();
|
|
|
|
|
this.mediaControl = (IMediaControl)this.graphBuilder;
|
|
|
|
|
this.videoWindow = (IVideoWindow)this.graphBuilder;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
DsError.ThrowExceptionForHR(hr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void StopCamera()
|
|
|
|
|
{
|
|
|
|
|
if (mediaControl != null)
|
|
|
|
|
{
|
|
|
|
|
int hr = mediaControl.StopWhenReady();
|
|
|
|
|
DsError.ThrowExceptionForHR(hr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (videoWindow != null)
|
|
|
|
|
{
|
|
|
|
|
videoWindow.put_Visible(OABool.False);
|
|
|
|
|
videoWindow.put_Owner(IntPtr.Zero);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Remove filter graph from the running object table.
|
|
|
|
|
if (rot != null)
|
|
|
|
|
{
|
|
|
|
|
rot.Dispose();
|
|
|
|
|
rot = null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (this.mediaControl != null)
|
|
|
|
|
{
|
|
|
|
|
Marshal.ReleaseComObject(this.mediaControl); this.mediaControl = null;
|
|
|
|
|
Marshal.ReleaseComObject(this.videoWindow); this.videoWindow = null;
|
|
|
|
|
Marshal.ReleaseComObject(this.graphBuilder); this.graphBuilder = null;
|
|
|
|
|
Marshal.ReleaseComObject(this.captureGraphBuilder); this.captureGraphBuilder = null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void SetupVideoWindow()
|
|
|
|
|
{
|
|
|
|
|
int hr = 0;
|
|
|
|
|
|
|
|
|
|
// Set the video window to be a child of the PictureBox
|
|
|
|
|
hr = this.videoWindow.put_Owner(pictureBox1.Handle);
|
|
|
|
|
DsError.ThrowExceptionForHR(hr);
|
|
|
|
|
|
|
|
|
|
hr = this.videoWindow.put_WindowStyle(WindowStyle.Child);
|
|
|
|
|
DsError.ThrowExceptionForHR(hr);
|
|
|
|
|
|
|
|
|
|
// Make the video window visible, now that it is properly positioned
|
|
|
|
|
hr = this.videoWindow.put_Visible(OABool.True);
|
|
|
|
|
DsError.ThrowExceptionForHR(hr);
|
|
|
|
|
|
|
|
|
|
// Set the video position
|
|
|
|
|
System.Drawing.Rectangle rc = pictureBox1.ClientRectangle;
|
|
|
|
|
hr = videoWindow.SetWindowPosition(0, 0, _pWidth, _pHeight);
|
|
|
|
|
DsError.ThrowExceptionForHR(hr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private void SetConfigParams(ICaptureGraphBuilder2 capGraph, IBaseFilter capFilter, int iFrameRate, int iWidth, int iHeight)
|
|
|
|
|
{
|
|
|
|
|
int hr;
|
|
|
|
|
object config;
|
|
|
|
|
AMMediaType mediaType;
|
|
|
|
|
// Find the stream config interface
|
|
|
|
|
hr = capGraph.FindInterface(
|
|
|
|
|
PinCategory.Capture, MediaType.Video, capFilter, typeof(IAMStreamConfig).GUID, out config);
|
|
|
|
|
|
|
|
|
|
IAMStreamConfig videoStreamConfig = config as IAMStreamConfig;
|
|
|
|
|
if (videoStreamConfig == null)
|
|
|
|
|
{
|
|
|
|
|
throw new Exception("Failed to get IAMStreamConfig");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Get the existing format block
|
|
|
|
|
hr = videoStreamConfig.GetFormat(out mediaType);
|
|
|
|
|
DsError.ThrowExceptionForHR(hr);
|
|
|
|
|
|
|
|
|
|
// copy out the videoinfoheader
|
|
|
|
|
VideoInfoHeader videoInfoHeader = new VideoInfoHeader();
|
|
|
|
|
Marshal.PtrToStructure(mediaType.formatPtr, videoInfoHeader);
|
|
|
|
|
|
|
|
|
|
// if overriding the framerate, set the frame rate
|
|
|
|
|
if (iFrameRate > 0)
|
|
|
|
|
{
|
|
|
|
|
videoInfoHeader.AvgTimePerFrame = 10000000 / iFrameRate;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// if overriding the width, set the width
|
|
|
|
|
if (iWidth > 0)
|
|
|
|
|
{
|
|
|
|
|
videoInfoHeader.BmiHeader.Width = iWidth;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// if overriding the Height, set the Height
|
|
|
|
|
if (iHeight > 0)
|
|
|
|
|
{
|
|
|
|
|
videoInfoHeader.BmiHeader.Height = iHeight;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Copy the media structure back
|
|
|
|
|
Marshal.StructureToPtr(videoInfoHeader, mediaType.formatPtr, false);
|
|
|
|
|
|
|
|
|
|
// Set the new format
|
|
|
|
|
hr = videoStreamConfig.SetFormat(mediaType);
|
|
|
|
|
DsError.ThrowExceptionForHR(hr);
|
|
|
|
|
|
|
|
|
|
DsUtils.FreeAMMediaType(mediaType);
|
|
|
|
|
mediaType = null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void SaveSizeInfo(ISampleGrabber sampleGrabber)
|
|
|
|
|
{
|
|
|
|
|
int hr;
|
|
|
|
|
|
|
|
|
|
// Get the media type from the SampleGrabber
|
|
|
|
|
AMMediaType media = new AMMediaType();
|
|
|
|
|
hr = sampleGrabber.GetConnectedMediaType(media);
|
|
|
|
|
DsError.ThrowExceptionForHR(hr);
|
|
|
|
|
|
|
|
|
|
if ((media.formatType != FormatType.VideoInfo) || (media.formatPtr == IntPtr.Zero))
|
|
|
|
|
{
|
|
|
|
|
throw new NotSupportedException("Unknown Grabber Media Format");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Grab the size info
|
|
|
|
|
VideoInfoHeader videoInfoHeader = (VideoInfoHeader)Marshal.PtrToStructure(media.formatPtr, typeof(VideoInfoHeader));
|
|
|
|
|
_pStride = _pWidth * (videoInfoHeader.BmiHeader.BitCount / 8);
|
|
|
|
|
|
|
|
|
|
DsUtils.FreeAMMediaType(media);
|
|
|
|
|
media = null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void ConfigureSampleGrabber(ISampleGrabber sampleGrabber)
|
|
|
|
|
{
|
|
|
|
|
AMMediaType media;
|
|
|
|
|
int hr;
|
|
|
|
|
|
|
|
|
|
// Set the media type to Video/RBG24
|
|
|
|
|
media = new AMMediaType();
|
|
|
|
|
media.majorType = MediaType.Video;
|
|
|
|
|
media.subType = MediaSubType.RGB24;
|
|
|
|
|
media.formatType = FormatType.VideoInfo;
|
|
|
|
|
|
|
|
|
|
hr = sampleGrabber.SetMediaType(media);
|
|
|
|
|
DsError.ThrowExceptionForHR(hr);
|
|
|
|
|
|
|
|
|
|
DsUtils.FreeAMMediaType(media);
|
|
|
|
|
media = null;
|
|
|
|
|
|
|
|
|
|
hr = sampleGrabber.SetCallback(this, 1);
|
|
|
|
|
DsError.ThrowExceptionForHR(hr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public int BufferCB(double SampleTime, IntPtr pBuffer, int BufferLen)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
if (isGrab)
|
|
|
|
|
{
|
|
|
|
|
Bitmap bmp = new Bitmap(_pWidth, _pHeight, _pStride, PixelFormat.Format24bppRgb, pBuffer);
|
|
|
|
|
bmp.RotateFlip(RotateFlipType.Rotate180FlipX);
|
|
|
|
|
this.BeginInvoke((MethodInvoker)delegate
|
|
|
|
|
{
|
|
|
|
|
// pictureBox2.BackgroundImage = bmp;
|
|
|
|
|
var saveName = string.Empty;
|
|
|
|
|
if (rowhisinfo != null)
|
|
|
|
|
{
|
|
|
|
|
saveName = $"{filePath}{$"{rowhisinfo.jianchaid}"}{$"{DateTime.Now.ToString("yyyyMMddhhmmssffff")}"}.jpg";
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
saveName = $"{filePath}{$"{DateTime.Now.ToString("yyyyMMddhhmmssffff")}"}.jpg";
|
|
|
|
|
}
|
|
|
|
|
//表示开启了选中区域 截图一下 当背景
|
|
|
|
|
if (isSelecting && overlayPanel.Visible)
|
|
|
|
|
{
|
|
|
|
|
// 外部设置背景图
|
|
|
|
|
overlayPanel.BackImage = bmp;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
#region 根据保存的配置进行裁剪
|
|
|
|
|
// 读取配置,不存在时返回null
|
|
|
|
|
var loadedConfig = ConfigHelper.Load<SelectionConfig>("selectionXY");
|
|
|
|
|
// 当存在有效配置时执行裁剪
|
|
|
|
|
if (_isselectionXY=="1" &&loadedConfig != null && loadedConfig.Width > 0 && loadedConfig.Height > 0)
|
|
|
|
|
{
|
|
|
|
|
// 创建选区矩形
|
|
|
|
|
var cropRect = new System.Drawing.Rectangle(
|
|
|
|
|
loadedConfig.X,
|
|
|
|
|
loadedConfig.Y,
|
|
|
|
|
loadedConfig.Width,
|
|
|
|
|
loadedConfig.Height);
|
|
|
|
|
|
|
|
|
|
// 执行裁剪(使用Clone保证原图不被释放)
|
|
|
|
|
using (bmp) // 释放原始位图
|
|
|
|
|
{
|
|
|
|
|
// 创建新Bitmap对象保存裁剪结果
|
|
|
|
|
var croppedBmp = bmp.Clone(cropRect, bmp.PixelFormat);
|
|
|
|
|
croppedBmp.Save(saveName);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else // 无有效配置时保存完整图片
|
|
|
|
|
{
|
|
|
|
|
bmp.Save(saveName);
|
|
|
|
|
}
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
// bmp.Save(saveName);
|
|
|
|
|
imagearray.Add(saveName);
|
|
|
|
|
// 使用 Invoke 方法确保在UI线程上更新标签的文本
|
|
|
|
|
if (label1.InvokeRequired)
|
|
|
|
|
{
|
|
|
|
|
label1.Invoke(new Action(() => label1.Text = imagearray.Count.ToString()));
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
label1.Text = imagearray.Count.ToString();
|
|
|
|
|
}
|
|
|
|
|
label1.Refresh();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
});
|
|
|
|
|
isGrab = false;
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public int SampleCB(double SampleTime, IMediaSample pSample)
|
|
|
|
|
{
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 点击"选区域"按钮
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="sender"></param>
|
|
|
|
|
/// <param name="e"></param>
|
|
|
|
|
private void button7_Click_1(object sender, EventArgs e)
|
|
|
|
|
{
|
|
|
|
|
// 清空选区
|
|
|
|
|
selectionRect = System.Drawing.Rectangle.Empty;
|
|
|
|
|
//截图
|
|
|
|
|
btn_Capture_Click(null,null);
|
|
|
|
|
// 显示遮罩层
|
|
|
|
|
overlayPanel.Visible = true;
|
|
|
|
|
|
|
|
|
|
// 进入选区模式
|
|
|
|
|
isSelecting = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#region 鼠标事件处理
|
|
|
|
|
// 鼠标按下事件处理
|
|
|
|
|
private void Overlay_MouseDown(object sender, MouseEventArgs e)
|
|
|
|
|
{
|
|
|
|
|
// 当处于选区模式且按下左键时
|
|
|
|
|
if (isSelecting && e.Button == MouseButtons.Left)
|
|
|
|
|
{
|
|
|
|
|
// 记录起始坐标点
|
|
|
|
|
startPoint = e.Location;
|
|
|
|
|
// 初始化选区矩形
|
|
|
|
|
selectionRect = new System.Drawing.Rectangle(e.Location, Size.Empty);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 鼠标移动事件处理
|
|
|
|
|
private void Overlay_MouseMove(object sender, MouseEventArgs e)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
// 当处于选区模式且按住左键拖动时
|
|
|
|
|
if (isSelecting && e.Button == MouseButtons.Left)
|
|
|
|
|
{
|
|
|
|
|
// 计算选区矩形参数
|
|
|
|
|
int x = Math.Min(startPoint.X, e.X);
|
|
|
|
|
int y = Math.Min(startPoint.Y, e.Y);
|
|
|
|
|
int width = Math.Abs(e.X - startPoint.X);
|
|
|
|
|
int height = Math.Abs(e.Y - startPoint.Y);
|
|
|
|
|
|
|
|
|
|
// 更新选区矩形
|
|
|
|
|
selectionRect = new System.Drawing.Rectangle(x, y, width, height);
|
|
|
|
|
|
|
|
|
|
// 限制选区在控件范围内
|
|
|
|
|
selectionRect = System.Drawing.Rectangle.Intersect(selectionRect, overlayPanel.ClientRectangle);
|
|
|
|
|
|
|
|
|
|
// 触发重绘更新选区显示
|
|
|
|
|
overlayPanel.Invalidate();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 鼠标释放事件处理
|
|
|
|
|
private void Overlay_MouseUp(object sender, MouseEventArgs e)
|
|
|
|
|
{
|
|
|
|
|
// 当结束选区操作时
|
|
|
|
|
if (isSelecting)
|
|
|
|
|
{
|
|
|
|
|
// 退出选区模式
|
|
|
|
|
isSelecting = false;
|
|
|
|
|
// 隐藏遮罩层
|
|
|
|
|
overlayPanel.Visible = false;
|
|
|
|
|
// 清除背景图
|
|
|
|
|
overlayPanel.BackImage = null;
|
|
|
|
|
// 转换到实际图像坐标系
|
|
|
|
|
System.Drawing.Rectangle imageCoords = GetImageCoordinates(selectionRect);
|
|
|
|
|
var config = new SelectionConfig
|
|
|
|
|
{
|
|
|
|
|
X = imageCoords.X,
|
|
|
|
|
Y = imageCoords.Y,
|
|
|
|
|
Width = imageCoords.Width,
|
|
|
|
|
Height = imageCoords.Height
|
|
|
|
|
};
|
|
|
|
|
//存储坐标
|
|
|
|
|
ConfigHelper.Save("selectionXY", config);
|
|
|
|
|
//// 显示坐标信息
|
|
|
|
|
//MessageBox.Show($"捕获的选区坐标:\n" +
|
|
|
|
|
// $"X={imageCoords.X}, Y={imageCoords.Y}\n" +
|
|
|
|
|
// $"宽={imageCoords.Width}, 高={imageCoords.Height}");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#region 绘制逻辑
|
|
|
|
|
private void pictureBox1_Paint(object sender, PaintEventArgs e)
|
|
|
|
|
{
|
|
|
|
|
//if (!selectionRect.IsEmpty)
|
|
|
|
|
//{
|
|
|
|
|
// using (Pen pen = new Pen(Color.Blue, 2)) // 蓝色边框
|
|
|
|
|
// {
|
|
|
|
|
// e.Graphics.DrawRectangle(pen, selectionRect);
|
|
|
|
|
// }
|
|
|
|
|
//}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 遮罩层绘制事件
|
|
|
|
|
private void Overlay_Paint(object sender, PaintEventArgs e)
|
|
|
|
|
{
|
|
|
|
|
// 当存在有效选区时进行绘制
|
|
|
|
|
if (!selectionRect.IsEmpty)
|
|
|
|
|
{
|
|
|
|
|
using (Pen pen = new Pen(Color.Red, 2)) // 2像素宽红色边框
|
|
|
|
|
using (Brush brush = new SolidBrush(Color.FromArgb(50, 255, 0, 0))) // 半透明红色填充
|
|
|
|
|
{
|
|
|
|
|
// 绘制半透明填充区域
|
|
|
|
|
e.Graphics.FillRectangle(brush, selectionRect);
|
|
|
|
|
// 绘制红色边框
|
|
|
|
|
e.Graphics.DrawRectangle(pen, selectionRect);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region 坐标转换方法
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 将控件坐标转换为实际图像坐标
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="controlRect">控件坐标系中的矩形</param>
|
|
|
|
|
/// <returns>实际图像坐标系中的矩形</returns>
|
|
|
|
|
private System.Drawing.Rectangle GetImageCoordinates(System.Drawing.Rectangle controlRect)
|
|
|
|
|
{
|
|
|
|
|
if (pictureBox1.SizeMode == PictureBoxSizeMode.Zoom)
|
|
|
|
|
{
|
|
|
|
|
// 检查图像是否存在
|
|
|
|
|
if (pictureBox1.Image == null)
|
|
|
|
|
return System.Drawing.Rectangle.Empty;
|
|
|
|
|
|
|
|
|
|
// 计算Zoom模式的缩放比例
|
|
|
|
|
float zoomRatio = Math.Min(
|
|
|
|
|
(float)pictureBox1.Width / pictureBox1.Image.Width,
|
|
|
|
|
(float)pictureBox1.Height / pictureBox1.Image.Height);
|
|
|
|
|
|
|
|
|
|
// 计算实际显示区域参数
|
|
|
|
|
int displayWidth = (int)(pictureBox1.Image.Width * zoomRatio);
|
|
|
|
|
int displayHeight = (int)(pictureBox1.Image.Height * zoomRatio);
|
|
|
|
|
int offsetX = (pictureBox1.Width - displayWidth) / 2;
|
|
|
|
|
int offsetY = (pictureBox1.Height - displayHeight) / 2;
|
|
|
|
|
|
|
|
|
|
// 执行坐标转换(考虑居中显示偏移)
|
|
|
|
|
return new System.Drawing.Rectangle(
|
|
|
|
|
(int)((controlRect.X - offsetX) / zoomRatio),
|
|
|
|
|
(int)((controlRect.Y - offsetY) / zoomRatio),
|
|
|
|
|
(int)(controlRect.Width / zoomRatio),
|
|
|
|
|
(int)(controlRect.Height / zoomRatio));
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// 如果SizeMode不是Zoom,直接返回
|
|
|
|
|
return controlRect;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
private void button8_Click(object sender, EventArgs e)
|
|
|
|
|
{
|
|
|
|
|
// 重新绘制选区
|
|
|
|
|
pictureBox1.Invalidate();
|
|
|
|
|
}
|
2024-12-11 19:48:43 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|