using AForge.Controls; using AForge.Imaging; using AForge.Video; using AForge.Video.FFMPEG; using DirectShowLib; 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; using System.Drawing.Imaging; 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; using System.Runtime.InteropServices.ComTypes; using System.Security.Policy; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Windows.Controls; using System.Windows.Documents; using System.Windows.Forms; using System.Windows.Shapes; using System.Xml.Linq; using static AForge.Imaging.Filters.HitAndMiss; using static System.Windows.Forms.VisualStyles.VisualStyleElement; namespace videoGather { public partial class video : Form, ISampleGrabberCB { public video() { InitializeComponent(); InitializeOverlay(); // 初始化透明遮罩层 } #region 属性 /// /// 设备源 /// 用来操作摄像头 /// private AForge.Video.DirectShow.VideoCaptureDevice videoCapture; /// /// 摄像头设备集合 /// private AForge.Video.DirectShow.FilterInfoCollection infoCollection; /// /// 图片 /// private System.Drawing.Bitmap imgMap; /// /// 文件保存路径 /// private readonly string filePath = Application.StartupPath + @"\"; /// /// 文件名称 /// private readonly string fileName = $"{DateTime.Now.ToString("yyyyMMddhhmmssffff")}"; /// /// 用与把每一帧图像写入到视频文件 /// private AForge.Video.FFMPEG.VideoFileWriter videoWriter; /// /// 是否开始录像 /// private bool IsStartVideo = false; /// /// 写入次数 /// private int tick_num = 0; /// /// 录制多少小时,只是为了定时间计算录制时间使用 /// private int Hour = 0; /// /// 计时器 /// private System.Timers.Timer timer_count; /// /// 视频保存名称 /// private string videoName = string.Empty; /// /// 路径地址 /// private string _url = string.Empty; /// /// 是否读取HIS信息 /// private string _ishisinfo = string.Empty; private string _path = string.Empty; /// /// 当前类型 /// private string _type = string.Empty; /// /// 病理截图临时存放位置 /// private string _blpath = string.Empty; /// /// 病理访问前缀 /// private string _blprefix = string.Empty; /// /// 病理截图热键 /// private string strkey = string.Empty; /// /// 区域截图设置 /// private string _xywh = string.Empty; /// /// 文件上传模式 /// private string _model = string.Empty; /// /// 体检患者信息地址 /// private string _InspectUrl = string.Empty; /// /// 是否开启体检编码扫码 /// private string _isInspect = string.Empty; /// /// 是否开启区域截图 /// private string _isselectionXY = string.Empty; //超声存放文件访问地址 ArrayList imagearray = new ArrayList(); /// /// 存放双击选择的患者数据 /// private HisInfo rowhisinfo; /// /// 存放自己新增的数据源 /// List hisInfos = new List(); 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 #endregion #region 窗口加载与关闭 /// /// 讲题加载事件 /// /// /// private void Form1_Load(object sender, EventArgs e) { // _pWidth = pictureBox1.Width; // _pHeight = pictureBox1.Height; dGVPatient.AutoGenerateColumns = false; // InitCamera(); InitCameraSelect(); //读取配置信息 _isInspect = ConfigurationManager.AppSettings["isInspect"]; _InspectUrl = ConfigurationManager.AppSettings["InspectUrl"]; _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"]; _ishisinfo = ConfigurationManager.AppSettings["ishisinfo"]; _isselectionXY = ConfigurationManager.AppSettings["isselectionXY"]; 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; if (_isInspect == "1") { label7.Visible = true; textBox1.Visible = true; } else { label7.Visible = false; textBox1.Visible = false; } 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 }); //秒表 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); if (_ishisinfo == "0") { button1.Visible = true; GetHisInfo(); } else { button1.Visible = false; } label4.Focus(); // 添加对窗口大小改变事件的订阅 // this.Resize += new EventHandler(Form1_Resize); } #region 初始化透明遮罩层 /// /// 初始化透明遮罩层 /// 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 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(); } } } } /// /// 窗口关闭时 /// /// /// private void Form1_FormClosing(object sender, FormClosingEventArgs e) { // EndCamera(); StopCamera(); } #endregion #region 实例化 /// /// 实例化摄像头 /// 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; ////根据读取到的摄像头加载选择项 //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) //{ // cb_CameraSelect.SelectedIndex = 0; //} devices = DsDevice.GetDevicesOfCat(FilterCategory.VideoInputDevice); for (int i = 0; i < devices.Length; i++) { this.cb_CameraSelect.Items.Add(devices[i].Name); } if (cb_CameraSelect.Items.Count > 0) { cb_CameraSelect.SelectedIndex = 1; //} } } #endregion #region 连接读取与关闭 /// /// 连接按钮 /// /// /// private void btn_Connect_Click(object sender, EventArgs e) { // 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) { MessageBox.Show("无视频源"); return; } else { DsDevice ds=null; foreach (var item in devices) { if(item.Name== this.cb_CameraSelect.SelectedItem) { ds = item; break; } } CaptureVideo(ds); } this.btn_Capture.Enabled = true; } /// /// 检查是否支持分辨率 /// /// /// /// 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); } /// /// 关闭按钮 /// /// /// private void btn_Close_Click(object sender, EventArgs e) { HookStop(); // EndCamera(); StopCamera(); } /// /// 关闭摄像头 /// public void EndCamera() { if (videoCapture != null) { // 先移除事件处理器 // 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; } } //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; //} } #endregion #region 拍照与保存 /// /// 拍照 /// /// /// private void btn_Capture_Click(object sender, EventArgs e) { try { #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; } catch (Exception ex) { MessageBox.Show(ex.Message+ex.StackTrace); } } /// /// 保存事件 /// /// /// private void btn_Save_Click(object sender, EventArgs e) { } #endregion #region 录像 /// /// 开始录像 /// /// /// 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); } } } } /// /// 暂停录像 /// /// /// 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; } } /// /// 停止录像 /// /// /// 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 计时器响应函数 /// /// 计时器 /// /// /// 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 /// /// 视频上传 /// /// /// 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); } } /// /// 指定Post地址使用Get 方式获取全部字符串 /// /// 请求后台地址 /// Post提交数据内容(utf-8编码的) /// public static string Post(string url, string content) { string result = ""; try { // 忽略证书验证 ServicePointManager.ServerCertificateValidationCallback += (sender, certificate, chain, sslPolicyErrors) => true; 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; } /// /// 指定Post地址使用Get 方式获取全部字符串 /// /// 请求后台地址 /// Post提交数据内容(utf-8编码的) /// public static string Post(string url, string content, string headerKey, string headerValue) { string result = ""; try { // 忽略证书验证 ServicePointManager.ServerCertificateValidationCallback += (sender, certificate, chain, sslPolicyErrors) => true; 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; } /// /// Get请求 /// /// 请求url /// public static string Get(string url) { try { // 忽略证书验证 ServicePointManager.ServerCertificateValidationCallback += (sender, certificate, chain, sslPolicyErrors) => true; 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; } } /// /// Get请求 /// /// /// /// /// public static string Get(string url, string headerKey, string headerValue) { try { // 忽略证书验证 ServicePointManager.ServerCertificateValidationCallback += (sender, certificate, chain, sslPolicyErrors) => true; 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; } } /// /// 获取HIS患者信息 /// public void GetHisInfo() { try { //存放绑定界面的患者数据 一个患者有多个检查 按照检查拆分 一个检查一条数据 List hisInfos = new List(); //获取福乐云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) { foreach (patientInfo item in FHEDM.rows) { foreach (projectsInfo projectsInfo in item.projects) { 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); } } } dGVPatient.DataSource = hisInfos; rowhisinfo = null; } } catch (Exception e) { MessageBox.Show("获取接口数据失败"); } } /// /// 获取福乐云HIS系统的token /// /// /// /// public string getHisToken(string url1, string appkey, string appsecret) { Dictionary dic = new Dictionary(); dic.Add("appkey", appkey); dic.Add("appsecret", appsecret); string resultV = PostFile3(url1, dic); FlyHisTokenMsgModel tm = JsonConvert.DeserializeObject(resultV); return tm.data.access_token; } /// /// 获取福乐云HIS系统的患者基本信息 /// /// /// /// public FlyHisEcgDataModel GetHisEcgData(string url1, string Yiyuanid, string kaifangsj, string token) { Dictionary dic = new Dictionary(); 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(resultV); return tm; } /// /// post form-data 参数 /// /// /// /// public string PostFile3(string url, Dictionary items) { // 忽略证书验证 ServicePointManager.ServerCertificateValidationCallback += (sender, certificate, chain, sslPolicyErrors) => true; 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 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 视频转换 /// /// 转换文件 /// /// /// 转换后文件 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 病理相关 /// /// 开启或关闭全局监测 /// /// /// 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 = "开启截图"; } } /// /// 保存病理截图并且转换成dcm /// private void SaveImageDcm() { Bitmap currentFrame = player.GetCurrentVideoFrame(); 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(); } } } /// /// 上传病理dcm并且传递数据 /// /// /// 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(msg); if (person != null) { InsPatientInfo(person.data); InsImageInfo(person.data, arrayList); MessageBox.Show("上传成功"); Imaganddcm.Array.Clear(); label5.Text = "0"; } } } /// /// 插入患者信息 /// /// 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); } /// /// 插入影像数据 /// /// /// private void InsImageInfo(string token, ArrayList arrayList) { if (arrayList != null) { int count = 0; List images = new List(); 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 } }; //患者信息 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 } }; List patientList = new List(); 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); //不是病理的 暂时不需要先注释了 //if (keyString == strkey) //{ // SaveImageDcm(); //} 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 /// /// 是否开启区域截图 /// /// /// 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; } } /// /// 双击患者列 选中患者 /// /// /// 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; } } /// /// 患者数据上传 /// /// /// 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(token); List Record = new List(); ExamRecord examRecord = new ExamRecord(); examRecord.examId = _isInspect == "1" ? rowhisinfo.jianchabh : rowhisinfo.jianchabh + "_" + GetRandomNumber(1, 100); examRecord.sfz = rowhisinfo.sfz; examRecord.pname = rowhisinfo.name; examRecord.gender = rowhisinfo.sex; examRecord.birthday = GetTimestampFromBirthdate(rowhisinfo.birthdate).ToString(); 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) { // 尝试解析日期字符串 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) { // 尝试解析日期字符串 DateTime birthDateTime; if (DateTime.TryParseExact(birthdate, "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture, DateTimeStyles.None, out birthDateTime)) { // 将本地时间转换为UTC时间 DateTime birthDateTimeUtc = birthDateTime.ToUniversalTime(); // 计算时间戳 return (long)birthDateTimeUtc.Subtract(new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalMilliseconds; } else { // 如果日期格式不正确,抛出异常或返回0 throw new ArgumentException("无效的日期格式。正确的格式应该是yyyy-MM-dd。"); // 或者返回0,取决于你希望如何处理错误 // return 0; } } /// /// 刷新患者 /// /// /// 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 调用接口上传文件 /// /// 调用接口上传文件 /// /// 文件所在的路径 /// 文件保存的文件夹路径 /// 文件名(不包含扩展名) /// 文件扩展名(例如 "png", "jpg", "txt") /// 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; } /// /// 文件转换成base64 /// /// /// /// 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 /// /// 添加患者 /// /// /// private void button6_Click(object sender, EventArgs e) { InfoForm infoForm = new InfoForm(); if (infoForm.ShowDialog() == DialogResult.OK) { //先赋空再绑定 dGVPatient.DataSource = null; hisInfos.Add(infoForm.info); dGVPatient.DataSource = hisInfos; rowhisinfo = null; } } 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(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; } } } 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("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 /// /// 点击"选区域"按钮 /// /// /// 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 坐标转换方法 /// /// 将控件坐标转换为实际图像坐标 /// /// 控件坐标系中的矩形 /// 实际图像坐标系中的矩形 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(); } } }