自己做的网站某个网页打开很慢韩国风格网站模板

当前位置: 首页 > news >正文

自己做的网站某个网页打开很慢,韩国风格网站模板,网站风格分析怎么写,咸宁网页定制wpf截屏系列 第一章 使用GDI实现截屏 第二章 使用DockPanel制作截屏框 第三章 实现截屏框热键截屏#xff08;本章#xff09; 第四章 实现截屏框实时截屏 第五章 使用ffmpeg命令行实现录屏 文章目录 wpf截屏系列前言一、实现步骤1、响应热键2、截屏显示#xff08;1#…wpf截屏系列 第一章 使用GDI实现截屏 第二章 使用DockPanel制作截屏框 第三章 实现截屏框热键截屏本章 第四章 实现截屏框实时截屏 第五章 使用ffmpeg命令行实现录屏 文章目录 wpf截屏系列前言一、实现步骤1、响应热键2、截屏显示1获取屏幕区域2截取并显示 3、自动捕获窗口1获取系统所有窗口2根据鼠标位置搜索窗口3效果预览 2、点击拖出截屏框1移动到点击位置2模拟按下事件3修正偏移4效果预览 3、反向拖动1判断边界2事件转移3修正边界4效果预览 4、截取图片5、设置粘贴板 二、关于dpi1、适配不同dpi2、不支持dpi实时修改1现象2尝试的解决方案 3、建议 三、完整代码四、效果预览1、截屏粘贴到qq2、截屏保存到文件 总结 前言 在《C# wpf 使用DockPanel实现截屏框》中我们实现了一个截屏框接下来就要实现相应的截屏功能了。获取截屏区域然后使用GDI截屏在这里不少的细节需要处理比如响应热键弹出截屏界面、点击拖出截屏框、截屏区域任意反向拖动、处理不同dpi下的坐标位置等等。 一、实现步骤 1、响应热键 我们直接使用win32 api的RegisterHotKey和UnregisterHotKey即可。在Window的SourceInitialized事件中注册热键如下是注册altd为热键的示例代码 [System.Runtime.InteropServices.DllImport(user32)] private static extern bool RegisterHotKey(IntPtr hWnd, int id, uint controlKey, uint virtualKey);[System.Runtime.InteropServices.DllImport(user32)] private static extern bool UnregisterHotKey(IntPtr hWnd, int id); HotKey是对RegisterHotKey、UnregisterHotKey做了封装的对象网上可以搜到此处略。 private void Window_SourceInitialized(object sender, EventArgs e){//注册altd热键,0x44为d,其他虚拟键值请查看https://learn.microsoft.com/zh-tw/windows/win32/inputdev/virtual-key-codesHotKey k new HotKey(this, HotKey.KeyFlags.MOD_ALT, 0x44);k.OnHotKey K_OnHotKey;Visibility Visibility.Collapsed;}2、截屏显示 1获取屏幕区域 我们需要使用win32 api获取屏幕区域采用wpf的方法取得的屏幕分辨率是基于dpi的就算是用PointToScreen进行转换在程序运行过程中改了系统dpi后依然会不准确所以需要直接取得屏幕的实际像素分辨率用于gdi截屏。 const int DESKTOPVERTRES 117;const int DESKTOPHORZRES 118;[DllImport(gdi32.dll)]static extern int GetDeviceCaps(IntPtr hdc, // handle to DC int nIndex // index of capability );[DllImport(user32.dll)]static extern IntPtr GetDC(IntPtr ptr);[DllImport(user32.dll, EntryPoint ReleaseDC)]static extern IntPtr ReleaseDC(IntPtr hWnd, IntPtr hDc);/// summary /// 获取真实设置的桌面分辨率大小 /// /summary static Size DESKTOP{get{IntPtr hdc GetDC(IntPtr.Zero);Size size new Size();size.Width GetDeviceCaps(hdc, DESKTOPHORZRES);size.Height GetDeviceCaps(hdc, DESKTOPVERTRES);ReleaseDC(IntPtr.Zero, hdc);return size;}}2截取并显示 利用上面步骤获取到的截屏区域结合《C# wpf 使用GDI实现截屏》里的简单截屏即完成。取得Bitmap对象后参考我的另一篇文章《C# wpf Bitmap转换成WriteableBitmapBitmapSource的方法》将其转换为转换成wpf对象然后通过ImageBrush赋值为控件的Background即可以显示在控件上。 //截屏并显示到窗口 void Snapshot() {//获取桌面实际分辨率可以解决程序运行后修改dpi截图区域不正常的问题var leftTop new Point(0, 0);var rightBottom new Point(DESKTOP.Width, DESKTOP.Height);var bitmap Snapshot((int)leftTop.X, (int)leftTop.Y, (int)(rightBottom.X - leftTop.X), (int)(rightBottom.Y - leftTop.Y));var bmp BitmapToWriteableBitmap(bitmap);bitmap.Dispose();//显示到窗口grdGlobal.Background new ImageBrush(bmp); } 3、自动捕获窗口 qq和微信的截屏都有自动捕获窗口功能我们也可以自己实现这种功能。 1获取系统所有窗口 通过win32 api可以枚举系统所有窗口我们需要将所有窗口的位置大小记录下来网上可以找到WindowList相关代码此处略。 //获取桌面所有窗口 _windows WindowList.GetAllWindows(); IntPtr hwnd new WindowInteropHelper(this).Handle; //去除不可见窗口以及自己 _windows.RemoveAll((ele) { return !ele.isVisible || ele.Handle hwnd; });2根据鼠标位置搜索窗口 //窗口是以z顺序排列的查找到第一个匹配的窗口即可 var screenPoint grdGlobal.PointToScreen(point); foreach (var window in _windows) {if (window.rect.Contains(screenPoint))//获取在鼠标所在区域的窗口{try{if (window.rect.Right window.rect.Left window.rect.Bottom window.rect.Top)//{var topLeft grdGlobal.PointFromScreen(window.rect.TopLeft);var bottomRight grdGlobal.PointFromScreen(window.rect.BottomRight);Thickness thickness new Thickness(topLeft.X, topLeft.Y, grdGlobal.ActualWidth - bottomRight.X, grdGlobal.ActualHeight - bottomRight.Y);//修正边界if (thickness.Left 0) thickness.Left 0;if (thickness.Top 0) thickness.Top 0;if (thickness.Right 0) thickness.Right 0;if (thickness.Bottom 0) thickness.Bottom 0;//将截屏框显示在窗口位置leftPanel.Width thickness.Left;topPanel.Height thickness.Top;rightPanel.Width thickness.Right;bottomPanel.Height thickness.Bottom;break;}}catch { }} }3效果预览 2、点击拖出截屏框 出现截屏界面之后参考qq或微信的实现第一次点击是可以拖出截屏框框选的。如果是采样绘制的方法很简单直接绘制矩形就可以了。但是基于控件要实现这个功能需要一定的技巧在《C# wpf 使用DockPanel实现截屏框》的基础上实现这个功能。 1移动到点击位置 在鼠标按下事件或移动实现中 //将截屏框移动到点击位置 leftPanel.Width p.X; topPanel.Height p.Y; rightPanel.Width grdGlobal.ActualWidth - p.X; bottomPanel.Height grdGlobal.ActualHeight - p.Y;2模拟按下事件 接着上面的代码thumb为右下角拖动点。 //手动触发截屏框滑块拖动事件 MouseButtonEventArgs downEvent new MouseButtonEventArgs(Mouse.PrimaryDevice, Environment.TickCount, MouseButton.Left) { RoutedEvent FrameworkElement.MouseLeftButtonDownEvent }; thumb.RaiseEvent(downEvent);3修正偏移 由于是模拟的点击事件可能会出现鼠标不在Thumb上的情况此时需要对thumb位置进行修正在Thumb的DragStarted事件中记录偏移。 //滑块需要的偏移量 Point? _thumbOffset; var thumb sender as FrameworkElement; if (!new Rect(0, 0, thumb.ActualWidth, thumb.ActualHeight).Contains(new Point(e.HorizontalOffset, e.VerticalOffset))) //鼠标起始位置超出了控件范围则记录中心点偏移在拖动时修正 {_thumbOffset new Point(e.HorizontalOffset - thumb.ActualWidth / 2, e.VerticalOffset - thumb.ActualHeight / 2); }在Thumb的DragDelta事件中添加修正逻辑 var horizontalChange e.HorizontalChange; var verticalChange e.VerticalChange; if (_thumbOffset ! null) //修正偏移 {horizontalChange _thumbOffset.Value.X;verticalChange _thumbOffset.Value.Y; } 4效果预览 3、反向拖动 这一步不是必须的但是有的话操作体验会更好比如qq和微信的截图就支持反向拖动。如果我们使用gdi或gdi绘制截屏框则天然支持反向拖动因为RECT的大小可以为负数。但是基于控件则有一定的难度了由于控件宽高不能为负数我们需要实现事件转移机制依然是在《C# wpf 使用DockPanel实现截屏框》的基础上实现这个功能。 1判断边界 原本《C# wpf 使用DockPanel实现截屏框》的逻辑的Thumb到了边界就不进行任何操作了现在要拓展为到达边界则进行事件转移。 横向的Thumb if (width 0) {leftPanel.Width left 0 ? left : 0;rightPanel.Width right 0 ? right : 0; } else{ //此处将事件转移到反方向的Thumb } 纵向的Thumb if (height 0) {topPanel.Height top 0 ? top : 0;bottomPanel.Height bottom 0 ? bottom : 0; } else { //此处将事件转移到反方向的Thumb } 2事件转移 //当前的Thumb触发鼠标弹起事件结束拖动 MouseButtonEventArgs upEvent new MouseButtonEventArgs(Mouse.PrimaryDevice, Environment.TickCount, MouseButton.Left) { RoutedEvent FrameworkElement.MouseLeftButtonUpEvent }; thumb.RaiseEvent(upEvent); //反方向的Thumb触发鼠标按下事件开始拖动 MouseButtonEventArgs downEvent new MouseButtonEventArgs(Mouse.PrimaryDevice, Environment.TickCount, MouseButton.Left) { RoutedEvent FrameworkElement.MouseLeftButtonDownEvent }; t.RaiseEvent(downEvent);3修正边界 完成上述两步之后已经可以做到反向拖动了但是会有个问题当多动过快的时截屏框的位置会发生移动要解决这个问题则需要在事件转移时修正边界位置即使两条边重合。 横向的Thumb if (thumb.HorizontalAlignment HorizontalAlignment.Left) //从左到右转移的修正 {leftPanel.Width grdGlobal.ActualWidth - rightPanel.Width; } else //从右到左转移的修正 {rightPanel.Width grdGlobal.ActualWidth - leftPanel.Width; }纵向的Thumb if (thumb.VerticalAlignment VerticalAlignment.Top)//从上到下转移的修正{topPanel.Height grdGlobal.ActualHeight - bottomPanel.Height;}else//从下到上转移的修正{bottomPanel.Height grdGlobal.ActualHeight - topPanel.Height;}4效果预览 4、截取图片 由于前面截取是整个桌面的图像保存时需要根据截屏框截取画面我们使用WriteableBitmap对象就可以实现。 //获取截屏框的图片 WriteableBitmap GetClipImage() {var bursh grdGlobal.Background as ImageBrush;if (bursh ! null){//裁剪//全屏图片var screenWb bursh.ImageSource as WriteableBitmap;//获取截取区域var leftTop clipRect.PointToScreen(new Point(0, 0));var rightBottom clipRect.PointToScreen(new Point(clipRect.ActualWidth, clipRect.ActualHeight));var rect new Int32Rect((int)leftTop.X, (int)leftTop.Y, (int)(rightBottom.X - leftTop.X), (int)(rightBottom.Y - leftTop.Y));//创建截取图片对象var wb new WriteableBitmap(rect.Width, rect.Height, 0, 0, screenWb.Format, null);//写入截取区域数据wb.WritePixels(rect, screenWb.BackBuffer, screenWb.PixelHeight * screenWb.BackBufferStride, screenWb.BackBufferStride, 0, 0);return wb;}return null; } 5、设置粘贴板 直接使用Clipboard.SetImage即可参数类型为BitmapSource是WriteableBitmap的基类。 Clipboard.SetImage(GetClipImage());二、关于dpi 1、适配不同dpi 有处理dpi不同的情况在任意dpi下都能正常截图。 2、不支持dpi实时修改 1现象 程序启动后实时修改dpi截屏显示的画面会模糊主要原因是不同api之间的dpi计算不统一。系统dpi实时修改后wpf界面会响应oloaded自动调整大小但部分程序内部的dpi比如getWindowRect是不会变化的尤其是渲染图片依然按照程序启动时的dpi去计算所以会进行缩放显示的画面必然模糊。 这里举一个具体的例子流程如下 win11 分辨率1920x1080 1、初始系统dpi为1201.25倍 2、程序启动 3、程序dpi为120 5、全屏窗口大小1536x864通过win32 api获取则是1920x1080截屏1920x1080显示截屏画面无损 6、系统dpi设置为961倍 7、此时程序dpi为120 8、全屏窗口大小1920x1080通过win32 api获取则是2400x1350截屏1920x1080显示截屏画面模糊。 按像素点绘制画面显示在左上角无法充满窗口。 2尝试的解决方案 笔者采样了多种方式尝试解决 1、提前缩放图片再显示。 2、参考微软解决dpi问题的方法。 3、使用gdi的graphics直接通过hdc以像素点为单位绘制。 4、使用gdi的bitblt进行hdc拷贝。 以上方法都没效果画面依然模糊。 3、建议 需要支持dpi实时改变可以将截图功能作为单独的程序响应热键后再启动。 三、完整代码 https://download.csdn.net/download/u013113678/88308050 说明截屏的操作方式和qq、微信差不多目前设置的热键为altd。 四、效果预览 1、截屏粘贴到qq 2、截屏保存到文件 总结 以上就是今天要讲的内容本文介绍了wpf截屏框热键截屏的方法。需要实现的功能还是比较多的而且有些功能难度也不小几经尝试才找到合适的实现方法至于实时改变dpi的模糊的问题这个目前的结论是无法解决这并不是wpf的局限用c mfc也不行除非存在一个设置程序全局dpi的win32 api接口笔者没有发现。所以这个问题目前只能通过独立程序启动解决。但是总的来说实现的效果是很不错的尤其是反向拖动通过事件转移的方式实现界面操作还是很流畅。