FromHandle

FromHandle

  
MFC 实际上是对内核对象HANDLE(如CDC的m_hDC,CWnd的m_hWnd)封装了这个句柄有关的所有操作,一个类生成一个新对象的时候这个句柄是无效的,要获得这个句柄,可以有两个方法,一个是Create来创建,另一个就是用Attach来与一个已有的句柄建立关联,实际上也就是给类的句柄 成员变量赋值。 而有个时候这个句柄不是由我们创建,但是我们要对它的 封装类进行操作,(mfc 框架)必需创建对应的封装类包装它
MFC 中对各种包含 内核对象的封装类都有FromHandle(HANDLE h)方法
FromHandle(HANDLE h) 先查找由用户定义的 内核对象的封装类, 如果找到直接返回,没有找到构造一个临时对象返回.
例如:
void CListViewEx::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
CListCtrl& ListCtrl=GetListCtrl();
//构造了一个句柄是lpDrawItemStruct->hDC包装类
CDC* pDC = (CDC *)CDC::FromHandle(lpDrawItemStruct->hDC);
}
折叠全部 展开全部 Win-10.0.22621.0 Quicker-1.44.13.0 动作ID:29c6dfe2-10d8-4391-9753-a695f715e57a 来源动作: v0 Log文件路径:C:\Users\Administrator\AppData\Local\Temp\quicker_121_100719-246_log.html 定位文件 复制文件 上传并复制网址 开始执行动作:121 2025-07-04 22:07:19 11动作初始化 130运行C#代码 [in]失败后停止【值/表达式】True [in]运行模式【值/表达式】normal_roslyn [in]脚本内容【值/表达式】using System;\r\n using System.Windows.Automation;\r\n using System.Collections.Generic;\r\n \r\n namespace WeChatContactReader\r\n {\r\n public class WeChatHelper\r\n {\r\n // Quicker 调用入口函数\r\n public static string Exec(Quicker.Public.IStepContext context)\r\n {\r\n IntPtr hwnd = new IntPtr(68326); // 硬编码微信窗口句柄,也可通过 context.GetVarValue("hwnd") 获取\r\n \r\n AutomationElement root = AutomationElement.FromHandle(hwnd);\r\n \r\n if (root == null)\r\n {\r\n return "无法获取微信窗口的自动化对象";\r\n }\r\n \r\n Condition condition = new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Text);\r\n AutomationElementCollection texts = root.FindAll(TreeScope.Descendants, condition);\r\n \r\n List<string> contactNames = new List<string>();\r\n \r\n foreach (AutomationElement element in texts)\r\n {\r\n string name = element.Current.Name.Trim();\r\n if (!string.IsNullOrEmpty(name) && IsValidContactName(name))\r\n {\r\n contactNames.Add(name);\r\n }\r\n }\r\n \r\n // 拼接结果并设置到 Quicker 变量中\r\n string result = string.Join("\n", contactNames);\r\n context.SetVarValue("contactNames", result); // 设置到 Quicker 变量 %contactNames%\r\n \r\n return $"成功识别 {contactNames.Count} 个好友昵称";\r\n }\r\n \r\n // 判断是否是有效的联系人名称\r\n private static bool IsValidContactName(string text)\r\n {\r\n if (text.Length < 2 || text.Length > 20) return false;\r\n foreach (char c in text)\r\n {\r\n if (!(char.IsLetterOrDigit(c) || IsChineseChar(c)))\r\n return false;\r\n }\r\n return true;\r\n }\r\n \r\n // 判断字符是否为中文字符\r\n private static bool IsChineseChar(char c)\r\n {\r\n return c >= 0x4E00 && c <= 0x9FFF;\r\n }\r\n }\r\n }\r\n [in]执行线程【值/表达式】ui [in]引用DLL库【值/表达式】 异常:编译失败, Compilation, (18,2): error CS1513: } expected (85,1): error CS1022: Type or namespace definition, or end-of-file expected (34,13): error CS0246: The type or namespace name 'AutomationElement' could not be found (are you missing a using directive or an assembly reference?) (34,38): error CS0103: The name 'AutomationElement' does not exist in the current context (41,13): error CS0246: The type or namespace name 'Condition' could not be found (are you missing a using directive or an assembly reference?) (41,39): error CS0246: The type or namespace name 'PropertyCondition' could not be found (are you missing a using directive or an assembly reference?) (41,57): error CS0103: The name 'AutomationElement' does not exist in the current context (42,13): error CS0246: The type or namespace name 'AutomationElementCollection' could not be found (are you missing a using directive or an assembly reference?) (46,22): error CS0246: The type or namespace name 'AutomationElement' could not be found (are you missing a using directive or an assembly reference?) 代码: 1. using System; 2. using System.Text; 3. using System.Reflection; 4. using System.IO; 5. using System.Net; 6. using System.Net.Http; 7. using System.Collections; 8. using System.Collections.Generic; 9. using System.Collections.Concurrent; 10. using System.Text.RegularExpressions; 11. using System.Threading.Tasks; 12. using System.Linq; 13. using System.Windows.Automation; 14. 15. namespace __ScriptExecution { 16. 17. public class __2q194u8j 18. { 19. 20. 21. // using System; 22. // using System.Windows.Automation; 23. // using System.Collections.Generic; 24. 25. namespace WeChatContactReader 26. { 27. public class WeChatHelper 28. { 29. // Quicker 调用入口函数 30. public static string Exec(Quicker.Public.IStepContext context) 31. { 32. IntPtr hwnd = new IntPtr(68326); // 硬编码微信窗口句柄,也可通过 context.GetVarValue("hwnd") 获取 33. 34. AutomationElement root = AutomationElement.FromHandle(hwnd); 35. 36. if (root == null) 37. { 38. return "无法获取微信窗口的自动化对象"; 39. } 40. 41. Condition condition = new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Text); 42. AutomationElementCollection texts = root.FindAll(TreeScope.Descendants, condition); 43. 44. List<string> contactNames = new List<string>(); 45. 46. foreach (AutomationElement element in texts) 47. { 48. string name = element.Current.Name.Trim(); 49. if (!string.IsNullOrEmpty(name) && IsValidContactName(name)) 50. { 51. contactNames.Add(name); 52. } 53. } 54. 55. // 拼接结果并设置到 Quicker 变量中 56. string result = string.Join("\n", contactNames); 57. context.SetVarValue("contactNames", result); // 设置到 Quicker 变量 %contactNames% 58. 59. return $"成功识别 {contactNames.Count} 个好友昵称"; 60. } 61. 62. // 判断是否是有效的联系人名称 63. private static bool IsValidContactName(string text) 64. { 65. if (text.Length < 2 || text.Length > 20) return false; 66. foreach (char c in text) 67. { 68. if (!(char.IsLetterOrDigit(c) || IsChineseChar(c))) 69. return false; 70. } 71. return true; 72. } 73. 74. // 判断字符是否为中文字符 75. private static bool IsChineseChar(char c) 76. { 77. return c >= 0x4E00 && c <= 0x9FFF; 78. } 79. } 80. } 81. 82. 83. 84. } 85. } 当前引用:C:\Program Files\Quicker\CommunityToolkit.Mvvm.dll C:\Program Files\Quicker\CSScriptLibrary.dll C:\Program Files\Quicker\Dapper.StrongName.dll C:\Program Files\Quicker\DotNetProjects.SVGImage.dll C:\Program Files\Quicker\DotNetProjects.Wpf.Extended.Toolkit.dll C:\Program Files\Quicker\FlaUI.Core.dll C:\Program Files\Quicker\FontAwesomeIconsWpf.dll C:\Program Files\Quicker\GongSolutions.WPF.DragDrop.dll C:\Program Files\Quicker\HandyControl.dll C:\Program Files\Quicker\HL.dll C:\Program Files\Quicker\ICSharpCode.AvalonEdit.dll C:\Program Files\Quicker\log4net.dll C:\Program Files\Quicker\MdXaml.dll C:\Program Files\Quicker\Microsoft.Bcl.AsyncInterfaces.dll C:\Program Files\Quicker\Microsoft.CodeAnalysis.CSharp.dll C:\Program Files\Quicker\Microsoft.CodeAnalysis.dll C:\Program Files\Quicker\Microsoft.Web.WebView2.Core.dll C:\Program Files\Quicker\Microsoft.WindowsAPICodePack.dll C:\Program Files\Quicker\Microsoft.WindowsAPICodePack.Shell.dll C:\Program Files\Quicker\NamedPipeWrapper.dll C:\Program Files\Quicker\NAudio.dll C:\Program Files\Quicker\Newtonsoft.Json.dll C:\Program Files\Quicker\Ninject.dll C:\Program Files\Quicker\NPOI.dll C:\Program Files\Quicker\PInvoke.User32.dll C:\Program Files\Quicker\PInvoke.Windows.Core.dll C:\Program Files\Quicker\Python.Runtime.dll C:\Program Files\Quicker\Quicker.3rd.dll C:\Program Files\Quicker\Quicker.Common.dll C:\Program Files\Quicker\Quicker.exe C:\Program Files\Quicker\Quicker.Public.dll C:\Program Files\Quicker\Semver.dll C:\Program Files\Quicker\System.Buffers.dll C:\Program Files\Quicker\System.Collections.Immutable.dll C:\Program Files\Quicker\System.Data.SQLite.dll C:\Program Files\Quicker\System.Memory.dll C:\Program Files\Quicker\System.Net.Http.Formatting.dll C:\Program Files\Quicker\System.Numerics.Vectors.dll C:\Program Files\Quicker\System.Reflection.Metadata.dll C:\Program Files\Quicker\System.Runtime.CompilerServices.Unsafe.dll C:\Program Files\Quicker\System.Threading.Tasks.Extensions.dll C:\Program Files\Quicker\ToastNotifications.dll C:\Program Files\Quicker\ToastNotifications.Messages.dll C:\Program Files\Quicker\WindowsInput.dll C:\Program Files\Quicker\Z.Expressions.Eval.dll C:\Users\Administrator\Documents\Quicker\_packages\cea.tools\0.1.54\CeaCore.0.1.54.0.dll C:\Users\Administrator\Documents\Quicker\_packages\cea.tools\0.1.54\CeaQuicker.0.1.54.0.dll C:\Users\Administrator\Documents\Quicker\_packages\cea.tools\0.1.54\CeaQuickerTools.0.1.54.0.dll C:\Users\Administrator\Documents\Quicker\_packages\cea.tools\0.1.54\CeaWin32.0.1.54.0.dll C:\Windows\Microsoft.Net\assembly\GAC_64\PresentationCore\v4.0_4.0.0.0__31bf3856ad364e35\PresentationCore.dll C:\Windows\Microsoft.Net\assembly\GAC_64\System.Data\v4.0_4.0.0.0__b77a5c561934e089\System.Data.dll C:\Windows\Microsoft.Net\assembly\GAC_64\System.EnterpriseServices\v4.0_4.0.0.0__b03f5f7f11d50a3a\System.EnterpriseServices.dll C:\Windows\Microsoft.Net\assembly\GAC_64\System.Transactions\v4.0_4.0.0.0__b77a5c561934e089\System.Transactions.dll C:\Windows\Microsoft.Net\assembly\GAC_64\System.Web\v4.0_4.0.0.0__b03f5f7f11d50a3a\System.Web.dll C:\Windows\Microsoft.Net\assembly\GAC_MSIL\Accessibility\v4.0_4.0.0.0__b03f5f7f11d50a3a\Accessibility.dll C:\Windows\Microsoft.Net\assembly\GAC_MSIL\Microsoft.CSharp\v4.0_4.0.0.0__b03f5f7f11d50a3a\Microsoft.CSharp.dll C:\Windows\Microsoft.Net\assembly\GAC_MSIL\mscorlib.resources\v4.0_4.0.0.0_zh-Hans_b77a5c561934e089\mscorlib.resources.dll C:\Windows\Microsoft.Net\assembly\GAC_MSIL\netstandard\v4.0_2.0.0.0__cc7b13ffcd2ddd51\netstandard.dll C:\Windows\Microsoft.Net\assembly\GAC_MSIL\PresentationCore.resources\v4.0_4.0.0.0_zh-Hans_31bf3856ad364e35\PresentationCore.resources.dll C:\Windows\Microsoft.Net\assembly\GAC_MSIL\PresentationFramework.Aero2\v4.0_4.0.0.0__31bf3856ad364e35\PresentationFramework.Aero2.dll C:\Windows\Microsoft.Net\assembly\GAC_MSIL\PresentationFramework.resources\v4.0_4.0.0.0_zh-Hans_31bf3856ad364e35\PresentationFramework.resources.dll C:\Windows\Microsoft.Net\assembly\GAC_MSIL\PresentationFramework\v4.0_4.0.0.0__31bf3856ad364e35\PresentationFramework.dll C:\Windows\Microsoft.Net\assembly\GAC_MSIL\PresentationFramework-SystemData\v4.0_4.0.0.0__b77a5c561934e089\PresentationFramework-SystemData.dll C:\Windows\Microsoft.Net\assembly\GAC_MSIL\PresentationFramework-SystemXml\v4.0_4.0.0.0__b77a5c561934e089\PresentationFramework-SystemXml.dll C:\Windows\Microsoft.Net\assembly\GAC_MSIL\PresentationFramework-SystemXmlLinq\v4.0_4.0.0.0__b77a5c561934e089\PresentationFramework-SystemXmlLinq.dll C:\Windows\Microsoft.Net\assembly\GAC_MSIL\SMDiagnostics\v4.0_4.0.0.0__b77a5c561934e089\SMDiagnostics.dll C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.ComponentModel.DataAnnotations\v4.0_4.0.0.0__31bf3856ad364e35\System.ComponentModel.DataAnnotations.dll C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Configuration\v4.0_4.0.0.0__b03f5f7f11d50a3a\System.Configuration.dll C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Core\v4.0_4.0.0.0__b77a5c561934e089\System.Core.dll C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Drawing\v4.0_4.0.0.0__b03f5f7f11d50a3a\System.Drawing.dll C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Dynamic\v4.0_4.0.0.0__b03f5f7f11d50a3a\System.Dynamic.dll C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Globalization\v4.0_4.0.0.0__b03f5f7f11d50a3a\System.Globalization.dll C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Net.Http.resources\v4.0_4.0.0.0_zh-Hans_b03f5f7f11d50a3a\System.Net.Http.resources.dll C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Net.Http\v4.0_4.0.0.0__b03f5f7f11d50a3a\System.Net.Http.dll C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Numerics\v4.0_4.0.0.0__b77a5c561934e089\System.Numerics.dll C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.resources\v4.0_4.0.0.0_zh-Hans_b77a5c561934e089\System.resources.dll C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Runtime.Caching\v4.0_4.0.0.0__b03f5f7f11d50a3a\System.Runtime.Caching.dll C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Runtime.InteropServices.RuntimeInformation\v4.0_4.0.0.0__b03f5f7f11d50a3a\System.Runtime.InteropServices.RuntimeInformation.dll C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Runtime.InteropServices.WindowsRuntime\v4.0_4.0.0.0__b03f5f7f11d50a3a\System.Runtime.InteropServices.WindowsRuntime.dll C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Runtime.Serialization\v4.0_4.0.0.0__b77a5c561934e089\System.Runtime.Serialization.dll C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Runtime.WindowsRuntime\v4.0_4.0.0.0__b77a5c561934e089\System.Runtime.WindowsRuntime.dll C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Runtime\v4.0_4.0.0.0__b03f5f7f11d50a3a\System.Runtime.dll C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Security.Cryptography.Algorithms\v4.0_4.0.0.0__b03f5f7f11d50a3a\System.Security.Cryptography.Algorithms.dll C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.ValueTuple\v4.0_4.0.0.0__cc7b13ffcd2ddd51\System.ValueTuple.dll C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Windows.Controls.Ribbon\v4.0_4.0.0.0__b77a5c561934e089\System.Windows.Controls.Ribbon.dll C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Windows.Forms\v4.0_4.0.0.0__b77a5c561934e089\System.Windows.Forms.dll C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Xaml\v4.0_4.0.0.0__b77a5c561934e089\System.Xaml.dll C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Xml.Linq\v4.0_4.0.0.0__b77a5c561934e089\System.Xml.Linq.dll C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Xml\v4.0_4.0.0.0__b77a5c561934e089\System.Xml.dll C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System\v4.0_4.0.0.0__b77a5c561934e089\System.dll C:\Windows\Microsoft.Net\assembly\GAC_MSIL\UIAutomationProvider\v4.0_4.0.0.0__31bf3856ad364e35\UIAutomationProvider.dll C:\Windows\Microsoft.Net\assembly\GAC_MSIL\UIAutomationTypes.resources\v4.0_4.0.0.0_zh-Hans_31bf3856ad364e35\UIAutomationTypes.resources.dll C:\Windows\Microsoft.Net\assembly\GAC_MSIL\UIAutomationTypes\v4.0_4.0.0.0__31bf3856ad364e35\UIAutomationTypes.dll C:\Windows\Microsoft.Net\assembly\GAC_MSIL\WindowsBase\v4.0_4.0.0.0__31bf3856ad364e35\WindowsBase.dll C:\Windows\Microsoft.Net\assembly\GAC_MSIL\WindowsFormsIntegration\v4.0_4.0.0.0__31bf3856ad364e35\WindowsFormsIntegration.dll C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Microsoft.CSharp.dll C:\Windows\Microsoft.NET\Framework64\v4.0.30319\mscorlib.dll C:\Windows\Microsoft.NET\Framework64\v4.0.30319\System.Core.dll C:\Windows\Microsoft.NET\Framework64\v4.0.30319\System.dll C:\Windows\Microsoft.NET\Framework64\v4.0.30319\System.Net.Http.dll C:\Windows\system32\WinMetadata\Windows.ApplicationModel.winmd C:\Windows\system32\WinMetadata\Windows.Devices.winmd C:\Windows\system32\WinMetadata\Windows.Foundation.winmd C:\Windows\system32\WinMetadata\Windows.Graphics.winmd C:\Windows\system32\WinMetadata\Windows.Management.winmd C:\Windows\system32\WinMetadata\Windows.Media.winmd C:\Windows\system32\WinMetadata\Windows.Storage.winmd C:\Windows\system32\WinMetadata\Windows.UI.winmd 在 rTc1KTvzg91oKUEE8r7.TjNcIivIvOgHbN6UMi2.EsrWRQiFgnX(String , String , String ) 在 rTc1KTvzg91oKUEE8r7.TjNcIivIvOgHbN6UMi2.dWDWRgENtHN(String , String , ActionExecuteContext ) 在 Quicker.Domain.Actions.X.BuiltinRunners.Other.RunCsScriptStep.r52t34kc9u4(ActionStep , ActionExecuteContext , XAction , String , ThreadType ) 在 Quicker.Domain.Actions.X.BuiltinRunners.Other.RunCsScriptStep.<>c__DisplayClass62_0.s39AhW2xkks() 在 Quicker.Domain.Actions.X.XActionHelper.ExecuteCommonAction(ActionExecuteContext context, ActionStep step, XAction action, Func`1 actionFunc, Action successAction, Action failAction, StepInParamDef stopIfErrorParam, StepOutParamDef isSuccessOutputParam) 步骤(sys:csscript)执行失败,原因:编译失败, Compilation, (18,2): error CS1513: } expected (85,1): error CS1022: Type or namespace definition, or end-of-file expected (34,13): error CS0246: The type or namespace name 'AutomationElement' could not be found (are you missing a using directive or an assembly reference?) (34,38): error CS0103: The name 'AutomationElement' does not exist in the current context (41,13): error CS0246: The type or namespace name 'Condition' could not be found (are you missing a using directive or an assembly reference?) (41,39): error CS0246: The type or namespace name 'PropertyCondition' could not be found (are you missing a using directive or an assembly reference?) (41,57): error CS0103: The name 'AutomationElement' does not exist in the current context (42,13): error CS0246: The type or namespace name 'AutomationElementCollection' could not be found (are you missing a using directive or an assembly reference?) (46,22): error CS0246: The type or namespace name 'AutomationElement' could not be found (are you missing a using directive or an assembly reference?) 代码: 1. using System; 2. using System.Text; 3. using System.Reflection; 4. using System.IO; 5. using System.Net; 6. using System.Net.Http; 7. using System.Collections; 8. using System.Collections.Generic; 9. using System.Collections.Concurrent; 10. using System.Text.RegularExpressions; 11. using System.Threading.Tasks; 12. using System.Linq; 13. using System.Windows.Automation; 14. 15. namespace __ScriptExecution { 16. 17. public class __2q194u8j 18. { 19. 20. 21. // using System; 22. // using System.Windows.Automation; 23. // using System.Collections.Generic; 24. 25. namespace WeChatContactReader 26. { 27. public class WeChatHelper 28. { 29. // Quicker 调用入口函数 30. public static string Exec(Quicker.Public.IStepContext context) 31. { 32. IntPtr hwnd = new IntPtr(68326); // 硬编码微信窗口句柄,也可通过 context.GetVarValue("hwnd") 获取 33. 34. AutomationElement root = AutomationElement.FromHandle(hwnd); 35. 36. if (root == null) 37. { 38. return "无法获取微信窗口的自动化对象"; 39. } 40. 41. Condition condition = new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Text); 42. AutomationElementCollection texts = root.FindAll(TreeScope.Descendants, condition); 43. 44. List<string> contactNames = new List<string>(); 45. 46. foreach (AutomationElement element in texts) 47. { 48. string name = element.Current.Name.Trim(); 49. if (!string.IsNullOrEmpty(name) && IsValidContactName(name)) 50. { 51. contactNames.Add(name); 52. } 53. } 54. 55. // 拼接结果并设置到 Quicker 变量中 56. string result = string.Join("\n", contactNames); 57. context.SetVarValue("contactNames", result); // 设置到 Quicker 变量 %contactNames% 58. 59. return $"成功识别 {contactNames.Count} 个好友昵称"; 60. } 61. 62. // 判断是否是有效的联系人名称 63. private static bool IsValidContactName(string text) 64. { 65. if (text.Length < 2 || text.Length > 20) return false; 66. foreach (char c in text) 67. { 68. if (!(char.IsLetterOrDigit(c) || IsChineseChar(c))) 69. return false; 70. } 71. return true; 72. } 73. 74. // 判断字符是否为中文字符 75. private static bool IsChineseChar(char c) 76. { 77. return c >= 0x4E00 && c <= 0x9FFF; 78. } 79. } 80. } 81. 82. 83. 84. } 85. } 当前引用:C:\Program Files\Quicker\CommunityToolkit.Mvvm.dll C:\Program Files\Quicker\CSScriptLibrary.dll C:\Program Files\Quicker\Dapper.StrongName.dll C:\Program Files\Quicker\DotNetProjects.SVGImage.dll C:\Program Files\Quicker\DotNetProjects.Wpf.Extended.Toolkit.dll C:\Program Files\Quicker\FlaUI.Core.dll C:\Program Files\Quicker\FontAwesomeIconsWpf.dll C:\Program Files\Quicker\GongSolutions.WPF.DragDrop.dll C:\Program Files\Quicker\HandyControl.dll C:\Program Files\Quicker\HL.dll C:\Program Files\Quicker\ICSharpCode.AvalonEdit.dll C:\Program Files\Quicker\log4net.dll C:\Program Files\Quicker\MdXaml.dll C:\Program Files\Quicker\Microsoft.Bcl.AsyncInterfaces.dll C:\Program Files\Quicker\Microsoft.CodeAnalysis.CSharp.dll C:\Program Files\Quicker\Microsoft.CodeAnalysis.dll C:\Program Files\Quicker\Microsoft.Web.WebView2.Core.dll C:\Program Files\Quicker\Microsoft.WindowsAPICodePack.dll C:\Program Files\Quicker\Microsoft.WindowsAPICodePack.Shell.dll C:\Program Files\Quicker\NamedPipeWrapper.dll C:\Program Files\Quicker\NAudio.dll C:\Program Files\Quicker\Newtonsoft.Json.dll C:\Program Files\Quicker\Ninject.dll C:\Program Files\Quicker\NPOI.dll C:\Program Files\Quicker\PInvoke.User32.dll C:\Program Files\Quicker\PInvoke.Windows.Core.dll C:\Program Files\Quicker\Python.Runtime.dll C:\Program Files\Quicker\Quicker.3rd.dll C:\Program Files\Quicker\Quicker.Common.dll C:\Program Files\Quicker\Quicker.exe C:\Program Files\Quicker\Quicker.Public.dll C:\Program Files\Quicker\Semver.dll C:\Program Files\Quicker\System.Buffers.dll C:\Program Files\Quicker\System.Collections.Immutable.dll C:\Program Files\Quicker\System.Data.SQLite.dll C:\Program Files\Quicker\System.Memory.dll C:\Program Files\Quicker\System.Net.Http.Formatting.dll C:\Program Files\Quicker\System.Numerics.Vectors.dll C:\Program Files\Quicker\System.Reflection.Metadata.dll C:\Program Files\Quicker\System.Runtime.CompilerServices.Unsafe.dll C:\Program Files\Quicker\System.Threading.Tasks.Extensions.dll C:\Program Files\Quicker\ToastNotifications.dll C:\Program Files\Quicker\ToastNotifications.Messages.dll C:\Program Files\Quicker\WindowsInput.dll C:\Program Files\Quicker\Z.Expressions.Eval.dll C:\Users\Administrator\Documents\Quicker\_packages\cea.tools\0.1.54\CeaCore.0.1.54.0.dll C:\Users\Administrator\Documents\Quicker\_packages\cea.tools\0.1.54\CeaQuicker.0.1.54.0.dll C:\Users\Administrator\Documents\Quicker\_packages\cea.tools\0.1.54\CeaQuickerTools.0.1.54.0.dll C:\Users\Administrator\Documents\Quicker\_packages\cea.tools\0.1.54\CeaWin32.0.1.54.0.dll C:\Windows\Microsoft.Net\assembly\GAC_64\PresentationCore\v4.0_4.0.0.0__31bf3856ad364e35\PresentationCore.dll C:\Windows\Microsoft.Net\assembly\GAC_64\System.Data\v4.0_4.0.0.0__b77a5c561934e089\System.Data.dll C:\Windows\Microsoft.Net\assembly\GAC_64\System.EnterpriseServices\v4.0_4.0.0.0__b03f5f7f11d50a3a\System.EnterpriseServices.dll C:\Windows\Microsoft.Net\assembly\GAC_64\System.Transactions\v4.0_4.0.0.0__b77a5c561934e089\System.Transactions.dll C:\Windows\Microsoft.Net\assembly\GAC_64\System.Web\v4.0_4.0.0.0__b03f5f7f11d50a3a\System.Web.dll C:\Windows\Microsoft.Net\assembly\GAC_MSIL\Accessibility\v4.0_4.0.0.0__b03f5f7f11d50a3a\Accessibility.dll C:\Windows\Microsoft.Net\assembly\GAC_MSIL\Microsoft.CSharp\v4.0_4.0.0.0__b03f5f7f11d50a3a\Microsoft.CSharp.dll C:\Windows\Microsoft.Net\assembly\GAC_MSIL\mscorlib.resources\v4.0_4.0.0.0_zh-Hans_b77a5c561934e089\mscorlib.resources.dll C:\Windows\Microsoft.Net\assembly\GAC_MSIL\netstandard\v4.0_2.0.0.0__cc7b13ffcd2ddd51\netstandard.dll C:\Windows\Microsoft.Net\assembly\GAC_MSIL\PresentationCore.resources\v4.0_4.0.0.0_zh-Hans_31bf3856ad364e35\PresentationCore.resources.dll C:\Windows\Microsoft.Net\assembly\GAC_MSIL\PresentationFramework.Aero2\v4.0_4.0.0.0__31bf3856ad364e35\PresentationFramework.Aero2.dll C:\Windows\Microsoft.Net\assembly\GAC_MSIL\PresentationFramework.resources\v4.0_4.0.0.0_zh-Hans_31bf3856ad364e35\PresentationFramework.resources.dll C:\Windows\Microsoft.Net\assembly\GAC_MSIL\PresentationFramework\v4.0_4.0.0.0__31bf3856ad364e35\PresentationFramework.dll C:\Windows\Microsoft.Net\assembly\GAC_MSIL\PresentationFramework-SystemData\v4.0_4.0.0.0__b77a5c561934e089\PresentationFramework-SystemData.dll C:\Windows\Microsoft.Net\assembly\GAC_MSIL\PresentationFramework-SystemXml\v4.0_4.0.0.0__b77a5c561934e089\PresentationFramework-SystemXml.dll C:\Windows\Microsoft.Net\assembly\GAC_MSIL\PresentationFramework-SystemXmlLinq\v4.0_4.0.0.0__b77a5c561934e089\PresentationFramework-SystemXmlLinq.dll C:\Windows\Microsoft.Net\assembly\GAC_MSIL\SMDiagnostics\v4.0_4.0.0.0__b77a5c561934e089\SMDiagnostics.dll C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.ComponentModel.DataAnnotations\v4.0_4.0.0.0__31bf3856ad364e35\System.ComponentModel.DataAnnotations.dll C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Configuration\v4.0_4.0.0.0__b03f5f7f11d50a3a\System.Configuration.dll C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Core\v4.0_4.0.0.0__b77a5c561934e089\System.Core.dll C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Drawing\v4.0_4.0.0.0__b03f5f7f11d50a3a\System.Drawing.dll C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Dynamic\v4.0_4.0.0.0__b03f5f7f11d50a3a\System.Dynamic.dll C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Globalization\v4.0_4.0.0.0__b03f5f7f11d50a3a\System.Globalization.dll C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Net.Http.resources\v4.0_4.0.0.0_zh-Hans_b03f5f7f11d50a3a\System.Net.Http.resources.dll C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Net.Http\v4.0_4.0.0.0__b03f5f7f11d50a3a\System.Net.Http.dll C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Numerics\v4.0_4.0.0.0__b77a5c561934e089\System.Numerics.dll C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.resources\v4.0_4.0.0.0_zh-Hans_b77a5c561934e089\System.resources.dll C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Runtime.Caching\v4.0_4.0.0.0__b03f5f7f11d50a3a\System.Runtime.Caching.dll C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Runtime.InteropServices.RuntimeInformation\v4.0_4.0.0.0__b03f5f7f11d50a3a\System.Runtime.InteropServices.RuntimeInformation.dll C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Runtime.InteropServices.WindowsRuntime\v4.0_4.0.0.0__b03f5f7f11d50a3a\System.Runtime.InteropServices.WindowsRuntime.dll C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Runtime.Serialization\v4.0_4.0.0.0__b77a5c561934e089\System.Runtime.Serialization.dll C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Runtime.WindowsRuntime\v4.0_4.0.0.0__b77a5c561934e089\System.Runtime.WindowsRuntime.dll C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Runtime\v4.0_4.0.0.0__b03f5f7f11d50a3a\System.Runtime.dll C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Security.Cryptography.Algorithms\v4.0_4.0.0.0__b03f5f7f11d50a3a\System.Security.Cryptography.Algorithms.dll C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.ValueTuple\v4.0_4.0.0.0__cc7b13ffcd2ddd51\System.ValueTuple.dll C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Windows.Controls.Ribbon\v4.0_4.0.0.0__b77a5c561934e089\System.Windows.Controls.Ribbon.dll C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Windows.Forms\v4.0_4.0.0.0__b77a5c561934e089\System.Windows.Forms.dll C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Xaml\v4.0_4.0.0.0__b77a5c561934e089\System.Xaml.dll C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Xml.Linq\v4.0_4.0.0.0__b77a5c561934e089\System.Xml.Linq.dll C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Xml\v4.0_4.0.0.0__b77a5c561934e089\System.Xml.dll C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System\v4.0_4.0.0.0__b77a5c561934e089\System.dll C:\Windows\Microsoft.Net\assembly\GAC_MSIL\UIAutomationProvider\v4.0_4.0.0.0__31bf3856ad364e35\UIAutomationProvider.dll C:\Windows\Microsoft.Net\assembly\GAC_MSIL\UIAutomationTypes.resources\v4.0_4.0.0.0_zh-Hans_31bf3856ad364e35\UIAutomationTypes.resources.dll C:\Windows\Microsoft.Net\assembly\GAC_MSIL\UIAutomationTypes\v4.0_4.0.0.0__31bf3856ad364e35\UIAutomationTypes.dll C:\Windows\Microsoft.Net\assembly\GAC_MSIL\WindowsBase\v4.0_4.0.0.0__31bf3856ad364e35\WindowsBase.dll C:\Windows\Microsoft.Net\assembly\GAC_MSIL\WindowsFormsIntegration\v4.0_4.0.0.0__31bf3856ad364e35\WindowsFormsIntegration.dll C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Microsoft.CSharp.dll C:\Windows\Microsoft.NET\Framework64\v4.0.30319\mscorlib.dll C:\Windows\Microsoft.NET\Framework64\v4.0.30319\System.Core.dll C:\Windows\Microsoft.NET\Framework64\v4.0.30319\System.dll C:\Windows\Microsoft.NET\Framework64\v4.0.30319\System.Net.Http.dll C:\Windows\system32\WinMetadata\Windows.ApplicationModel.winmd C:\Windows\system32\WinMetadata\Windows.Devices.winmd C:\Windows\system32\WinMetadata\Windows.Foundation.winmd C:\Windows\system32\WinMetadata\Windows.Graphics.winmd C:\Windows\system32\WinMetadata\Windows.Management.winmd C:\Windows\system32\WinMetadata\Windows.Media.winmd C:\Windows\system32\WinMetadata\Windows.Storage.winmd C:\Windows\system32\WinMetadata\Windows.UI.winmd 停止动作:编译失败, Compilation, (18,2): error CS1513: } expected (85,1): error CS1022: Type or namespace definition, or end-of-file expected (34,13): error CS0246: The type or namespace name 'AutomationElement' could not be found (are you missing a using directive or an assembly reference?) (34,38): error CS0103: The name 'AutomationElement' does not exist in the current context (41,13): error CS0246: The type or namespace name 'Condition' could not be found (are you missing a using directive or an assembly reference?) (41,39): error CS0246: The type or namespace name 'PropertyCondition' could not be found (are you missing a using directive or an assembly reference?) (41,57): error CS0103: The name 'AutomationElement' does not exist in the current context (42,13): error CS0246: The type or namespace name 'AutomationElementCollection' could not be found (are you missing a using directive or an assembly reference?) (46,22): error CS0246: The type or namespace name 'AutomationElement' could not be found (are you missing a using directive or an assembly reference?) 代码: 1. using System; 2. using System.Text; 3. using System.Reflection; 4. using System.IO; 5. using System.Net; 6. using System.Net.Http; 7. using System.Collections; 8. using System.Collections.Generic; 9. using System.Collections.Concurrent; 10. using System.Text.RegularExpressions; 11. using System.Threading.Tasks; 12. using System.Linq; 13. using System.Windows.Automation; 14. 15. namespace __ScriptExecution { 16. 17. public class __2q194u8j 18. { 19. 20. 21. // using System; 22. // using System.Windows.Automation; 23. // using System.Collections.Generic; 24. 25. namespace WeChatContactReader 26. { 27. public class WeChatHelper 28. { 29. // Quicker 调用入口函数 30. public static string Exec(Quicker.Public.IStepContext context) 31. { 32. IntPtr hwnd = new IntPtr(68326); // 硬编码微信窗口句柄,也可通过 context.GetVarValue("hwnd") 获取 33. 34. AutomationElement root = AutomationElement.FromHandle(hwnd); 35. 36. if (root == null) 37. { 38. return "无法获取微信窗口的自动化对象"; 39. } 40. 41. Condition condition = new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Text); 42. AutomationElementCollection texts = root.FindAll(TreeScope.Descendants, condition); 43. 44. List<string> contactNames = new List<string>(); 45. 46. foreach (AutomationElement element in texts) 47. { 48. string name = element.Current.Name.Trim(); 49. if (!string.IsNullOrEmpty(name) && IsValidContactName(name)) 50. { 51. contactNames.Add(name); 52. } 53. } 54. 55. // 拼接结果并设置到 Quicker 变量中 56. string result = string.Join("\n", contactNames); 57. context.SetVarValue("contactNames", result); // 设置到 Quicker 变量 %contactNames% 58. 59. return $"成功识别 {contactNames.Count} 个好友昵称"; 60. } 61. 62. // 判断是否是有效的联系人名称 63. private static bool IsValidContactName(string text) 64. { 65. if (text.Length < 2 || text.Length > 20) return false; 66. foreach (char c in text) 67. { 68. if (!(char.IsLetterOrDigit(c) || IsChineseChar(c))) 69. return false; 70. } 71. return true; 72. } 73. 74. // 判断字符是否为中文字符 75. private static bool IsChineseChar(char c) 76. { 77. return c >= 0x4E00 && c <= 0x9FFF; 78. } 79. } 80. } 81. 82. 83. 84. } 85. } 当前引用:C:\Program Files\Quicker\CommunityToolkit.Mvvm.dll C:\Program Files\Quicker\CSScriptLibrary.dll C:\Program Files\Quicker\Dapper.StrongName.dll C:\Program Files\Quicker\DotNetProjects.SVGImage.dll C:\Program Files\Quicker\DotNetProjects.Wpf.Extended.Toolkit.dll C:\Program Files\Quicker\FlaUI.Core.dll C:\Program Files\Quicker\FontAwesomeIconsWpf.dll C:\Program Files\Quicker\GongSolutions.WPF.DragDrop.dll C:\Program Files\Quicker\HandyControl.dll C:\Program Files\Quicker\HL.dll C:\Program Files\Quicker\ICSharpCode.AvalonEdit.dll C:\Program Files\Quicker\log4net.dll C:\Program Files\Quicker\MdXaml.dll C:\Program Files\Quicker\Microsoft.Bcl.AsyncInterfaces.dll C:\Program Files\Quicker\Microsoft.CodeAnalysis.CSharp.dll C:\Program Files\Quicker\Microsoft.CodeAnalysis.dll C:\Program Files\Quicker\Microsoft.Web.WebView2.Core.dll C:\Program Files\Quicker\Microsoft.WindowsAPICodePack.dll C:\Program Files\Quicker\Microsoft.WindowsAPICodePack.Shell.dll C:\Program Files\Quicker\NamedPipeWrapper.dll C:\Program Files\Quicker\NAudio.dll C:\Program Files\Quicker\Newtonsoft.Json.dll C:\Program Files\Quicker\Ninject.dll C:\Program Files\Quicker\NPOI.dll C:\Program Files\Quicker\PInvoke.User32.dll C:\Program Files\Quicker\PInvoke.Windows.Core.dll C:\Program Files\Quicker\Python.Runtime.dll C:\Program Files\Quicker\Quicker.3rd.dll C:\Program Files\Quicker\Quicker.Common.dll C:\Program Files\Quicker\Quicker.exe C:\Program Files\Quicker\Quicker.Public.dll C:\Program Files\Quicker\Semver.dll C:\Program Files\Quicker\System.Buffers.dll C:\Program Files\Quicker\System.Collections.Immutable.dll C:\Program Files\Quicker\System.Data.SQLite.dll C:\Program Files\Quicker\System.Memory.dll C:\Program Files\Quicker\System.Net.Http.Formatting.dll C:\Program Files\Quicker\System.Numerics.Vectors.dll C:\Program Files\Quicker\System.Reflection.Metadata.dll C:\Program Files\Quicker\System.Runtime.CompilerServices.Unsafe.dll C:\Program Files\Quicker\System.Threading.Tasks.Extensions.dll C:\Program Files\Quicker\ToastNotifications.dll C:\Program Files\Quicker\ToastNotifications.Messages.dll C:\Program Files\Quicker\WindowsInput.dll C:\Program Files\Quicker\Z.Expressions.Eval.dll C:\Users\Administrator\Documents\Quicker\_packages\cea.tools\0.1.54\CeaCore.0.1.54.0.dll C:\Users\Administrator\Documents\Quicker\_packages\cea.tools\0.1.54\CeaQuicker.0.1.54.0.dll C:\Users\Administrator\Documents\Quicker\_packages\cea.tools\0.1.54\CeaQuickerTools.0.1.54.0.dll C:\Users\Administrator\Documents\Quicker\_packages\cea.tools\0.1.54\CeaWin32.0.1.54.0.dll C:\Windows\Microsoft.Net\assembly\GAC_64\PresentationCore\v4.0_4.0.0.0__31bf3856ad364e35\PresentationCore.dll C:\Windows\Microsoft.Net\assembly\GAC_64\System.Data\v4.0_4.0.0.0__b77a5c561934e089\System.Data.dll C:\Windows\Microsoft.Net\assembly\GAC_64\System.EnterpriseServices\v4.0_4.0.0.0__b03f5f7f11d50a3a\System.EnterpriseServices.dll C:\Windows\Microsoft.Net\assembly\GAC_64\System.Transactions\v4.0_4.0.0.0__b77a5c561934e089\System.Transactions.dll C:\Windows\Microsoft.Net\assembly\GAC_64\System.Web\v4.0_4.0.0.0__b03f5f7f11d50a3a\System.Web.dll C:\Windows\Microsoft.Net\assembly\GAC_MSIL\Accessibility\v4.0_4.0.0.0__b03f5f7f11d50a3a\Accessibility.dll C:\Windows\Microsoft.Net\assembly\GAC_MSIL\Microsoft.CSharp\v4.0_4.0.0.0__b03f5f7f11d50a3a\Microsoft.CSharp.dll C:\Windows\Microsoft.Net\assembly\GAC_MSIL\mscorlib.resources\v4.0_4.0.0.0_zh-Hans_b77a5c561934e089\mscorlib.resources.dll C:\Windows\Microsoft.Net\assembly\GAC_MSIL\netstandard\v4.0_2.0.0.0__cc7b13ffcd2ddd51\netstandard.dll C:\Windows\Microsoft.Net\assembly\GAC_MSIL\PresentationCore.resources\v4.0_4.0.0.0_zh-Hans_31bf3856ad364e35\PresentationCore.resources.dll C:\Windows\Microsoft.Net\assembly\GAC_MSIL\PresentationFramework.Aero2\v4.0_4.0.0.0__31bf3856ad364e35\PresentationFramework.Aero2.dll C:\Windows\Microsoft.Net\assembly\GAC_MSIL\PresentationFramework.resources\v4.0_4.0.0.0_zh-Hans_31bf3856ad364e35\PresentationFramework.resources.dll C:\Windows\Microsoft.Net\assembly\GAC_MSIL\PresentationFramework\v4.0_4.0.0.0__31bf3856ad364e35\PresentationFramework.dll C:\Windows\Microsoft.Net\assembly\GAC_MSIL\PresentationFramework-SystemData\v4.0_4.0.0.0__b77a5c561934e089\PresentationFramework-SystemData.dll C:\Windows\Microsoft.Net\assembly\GAC_MSIL\PresentationFramework-SystemXml\v4.0_4.0.0.0__b77a5c561934e089\PresentationFramework-SystemXml.dll C:\Windows\Microsoft.Net\assembly\GAC_MSIL\PresentationFramework-SystemXmlLinq\v4.0_4.0.0.0__b77a5c561934e089\PresentationFramework-SystemXmlLinq.dll C:\Windows\Microsoft.Net\assembly\GAC_MSIL\SMDiagnostics\v4.0_4.0.0.0__b77a5c561934e089\SMDiagnostics.dll C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.ComponentModel.DataAnnotations\v4.0_4.0.0.0__31bf3856ad364e35\System.ComponentModel.DataAnnotations.dll C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Configuration\v4.0_4.0.0.0__b03f5f7f11d50a3a\System.Configuration.dll C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Core\v4.0_4.0.0.0__b77a5c561934e089\System.Core.dll C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Drawing\v4.0_4.0.0.0__b03f5f7f11d50a3a\System.Drawing.dll C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Dynamic\v4.0_4.0.0.0__b03f5f7f11d50a3a\System.Dynamic.dll C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Globalization\v4.0_4.0.0.0__b03f5f7f11d50a3a\System.Globalization.dll C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Net.Http.resources\v4.0_4.0.0.0_zh-Hans_b03f5f7f11d50a3a\System.Net.Http.resources.dll C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Net.Http\v4.0_4.0.0.0__b03f5f7f11d50a3a\System.Net.Http.dll C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Numerics\v4.0_4.0.0.0__b77a5c561934e089\System.Numerics.dll C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.resources\v4.0_4.0.0.0_zh-Hans_b77a5c561934e089\System.resources.dll C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Runtime.Caching\v4.0_4.0.0.0__b03f5f7f11d50a3a\System.Runtime.Caching.dll C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Runtime.InteropServices.RuntimeInformation\v4.0_4.0.0.0__b03f5f7f11d50a3a\System.Runtime.InteropServices.RuntimeInformation.dll C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Runtime.InteropServices.WindowsRuntime\v4.0_4.0.0.0__b03f5f7f11d50a3a\System.Runtime.InteropServices.WindowsRuntime.dll C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Runtime.Serialization\v4.0_4.0.0.0__b77a5c561934e089\System.Runtime.Serialization.dll C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Runtime.WindowsRuntime\v4.0_4.0.0.0__b77a5c561934e089\System.Runtime.WindowsRuntime.dll C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Runtime\v4.0_4.0.0.0__b03f5f7f11d50a3a\System.Runtime.dll C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Security.Cryptography.Algorithms\v4.0_4.0.0.0__b03f5f7f11d50a3a\System.Security.Cryptography.Algorithms.dll C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.ValueTuple\v4.0_4.0.0.0__cc7b13ffcd2ddd51\System.ValueTuple.dll C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Windows.Controls.Ribbon\v4.0_4.0.0.0__b77a5c561934e089\System.Windows.Controls.Ribbon.dll C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Windows.Forms\v4.0_4.0.0.0__b77a5c561934e089\System.Windows.Forms.dll C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Xaml\v4.0_4.0.0.0__b77a5c561934e089\System.Xaml.dll C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Xml.Linq\v4.0_4.0.0.0__b77a5c561934e089\System.Xml.Linq.dll C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Xml\v4.0_4.0.0.0__b77a5c561934e089\System.Xml.dll C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System\v4.0_4.0.0.0__b77a5c561934e089\System.dll C:\Windows\Microsoft.Net\assembly\GAC_MSIL\UIAutomationProvider\v4.0_4.0.0.0__31bf3856ad364e35\UIAutomationProvider.dll C:\Windows\Microsoft.Net\assembly\GAC_MSIL\UIAutomationTypes.resources\v4.0_4.0.0.0_zh-Hans_31bf3856ad364e35\UIAutomationTypes.resources.dll C:\Windows\Microsoft.Net\assembly\GAC_MSIL\UIAutomationTypes\v4.0_4.0.0.0__31bf3856ad364e35\UIAutomationTypes.dll C:\Windows\Microsoft.Net\assembly\GAC_MSIL\WindowsBase\v4.0_4.0.0.0__31bf3856ad364e35\WindowsBase.dll C:\Windows\Microsoft.Net\assembly\GAC_MSIL\WindowsFormsIntegration\v4.0_4.0.0.0__31bf3856ad364e35\WindowsFormsIntegration.dll C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Microsoft.CSharp.dll C:\Windows\Microsoft.NET\Framework64\v4.0.30319\mscorlib.dll C:\Windows\Microsoft.NET\Framework64\v4.0.30319\System.Core.dll C:\Windows\Microsoft.NET\Framework64\v4.0.30319\System.dll C:\Windows\Microsoft.NET\Framework64\v4.0.30319\System.Net.Http.dll C:\Windows\system32\WinMetadata\Windows.ApplicationModel.winmd C:\Windows\system32\WinMetadata\Windows.Devices.winmd C:\Windows\system32\WinMetadata\Windows.Foundation.winmd C:\Windows\system32\WinMetadata\Windows.Graphics.winmd C:\Windows\system32\WinMetadata\Windows.Management.winmd C:\Windows\system32\WinMetadata\Windows.Media.winmd C:\Windows\system32\WinMetadata\Windows.Storage.winmd C:\Windows\system32\WinMetadata\Windows.UI.winmd 耗时:110ms 检测到了中止标志(OperationFailed),停止后续步骤执行。 动作结束。耗时:124.4951ms
07-05
void CMyPS2Dlg::OnPaint() { CPaintDC dc(this); CRect clientRect; GetClientRect(&clientRect); if (m_memDC.GetSafeHdc() == NULL || m_memBitmap.GetSafeHandle() == NULL || GetBitmapDimension(m_memBitmap) != clientRect.Size()) { if (m_memDC.GetSafeHdc()) { m_memDC.SelectObject((HBITMAP)NULL); // 必须先取消选择位图 m_memDC.DeleteDC(); } if (m_memBitmap.GetSafeHandle()) { m_memBitmap.DeleteObject(); } CDC dcScreen; dcScreen.CreateDC(_T(“DISPLAY”), NULL, NULL, NULL); m_memDC.CreateCompatibleDC(&dcScreen); m_memBitmap.CreateCompatibleBitmap(&dcScreen, clientRect.Width(), clientRect.Height()); CBitmap* pOldBitmap = m_memDC.SelectObject(&m_memBitmap); if (pOldBitmap) { pOldBitmap->DeleteObject(); // 删除默认的位图对象 } dcScreen.DeleteDC(); } m_memDC.FillSolidRect(clientRect, GetSysColor(COLOR_BTNFACE)); Gdiplus::Graphics graphics(m_memDC); // 2. 绘制底层(未选中的图层) ImageLayer* bottomLayer = m_layer1.isSelected ? &m_layer2 : &m_layer1; if (bottomLayer->isVisible && !bottomLayer->displayImage.IsNull()) { DrawLayer(graphics, bottomLayer->displayImage, bottomLayer->alpha); } // 3. 绘制上层(选中的图层) ImageLayer* topLayer = m_layer1.isSelected ? &m_layer1 : &m_layer2; if (topLayer->isVisible && !topLayer->displayImage.IsNull()) { DrawLayer(graphics, topLayer->displayImage, topLayer->alpha); // 4. 在选中的图层上绘制选区 if (!m_rcSelection.IsRectNull() || !m_freeFormPoints.empty()) { DrawSelection(m_memDC, topLayer); } } if (m_bDoodleMode && !m_doodleTempImage.IsNull()) { CRect imgRect = GetImageClientRect(topLayer->image); std::unique_ptr<Gdiplus::Bitmap> gdiBitmap(CImageToGdiPlusBitmap(m_doodleTempImage)); if (gdiBitmap) { graphics.DrawImage( gdiBitmap.get(), Gdiplus::Rect(imgRect.left, imgRect.top, imgRect.Width(), imgRect.Height()), 0, 0, m_doodleTempImage.GetWidth(), m_doodleTempImage.GetHeight(), Gdiplus::UnitPixel ); } } // 绘制克隆区域 ImageLayer& activeLayer = m_layer1.isSelected ? m_layer1 : m_layer2; if (activeLayer.clonedRegion.active && activeLayer.clonedRegion.visible) { CRect srcRect(0, 0, activeLayer.clonedRegion.image.GetWidth(), activeLayer.clonedRegion.image.GetHeight()); CRect screenRect = ConvertToScreenRect(activeLayer.clonedRegion.destRect); std::unique_ptr<Gdiplus::Bitmap> gdiBitmap( CImageToGdiPlusBitmap(activeLayer.clonedRegion.image)); if (gdiBitmap) { graphics.DrawImage(gdiBitmap.get(), Gdiplus::Rect(screenRect.left, screenRect.top, screenRect.Width(), screenRect.Height()), 0, 0, srcRect.Width(), srcRect.Height(), Gdiplus::UnitPixel); } } // 5. 输出到屏幕 dc.BitBlt(0, 0, clientRect.Width(), clientRect.Height(), &m_memDC, 0, 0, SRCCOPY); } void CMyPS2Dlg::DrawLayer(Gdiplus::Graphics& graphics, CImage& image, float alpha) { CRect imgRect = GetImageClientRect(image); std::unique_ptrGdiplus::Bitmap gdiBitmap(CImageToGdiPlusBitmap(image)); if (gdiBitmap) { Gdiplus::ColorMatrix matrix = { 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, alpha, 0, 0, 0, 0, 0, 1 }; Gdiplus::ImageAttributes attr; attr.SetColorMatrix(&matrix); graphics.DrawImage( gdiBitmap.get(), Gdiplus::Rect(imgRect.left, imgRect.top, imgRect.Width(), imgRect.Height()), 0, 0, image.GetWidth(), image.GetHeight(), Gdiplus::UnitPixel, &attr ); } } void CMyPS2Dlg::DrawSelection(CDC& dc, ImageLayer* layer) { if (m_selectionMode == SELECT_RECTANGLE && !m_rcSelection.IsRectNull()) { //将图像坐标的选区转换为屏幕坐标 CRect selRect = ConvertToScreenRect(m_rcSelection); // 区分选中状态保持状态 if (m_bSelecting) { // 动态选区:使用XOR模式(无闪烁拖动) CPen pen(PS_DOT, 1, RGB(255, 0, 0)); CPen* pOldPen = m_memDC.SelectObject(&pen); m_memDC.SelectStockObject(NULL_BRUSH); int oldROP = m_memDC.SetROP2(R2_XORPEN); m_memDC.Rectangle(selRect); m_memDC.SetROP2(oldROP); m_memDC.SelectObject(pOldPen); pen.DeleteObject(); } else { // 静态选区:使用常规绘制(保持可见) CPen pen(PS_SOLID, 1, RGB(0, 255, 0)); // 绿色实线 CPen* pOldPen = m_memDC.SelectObject(&pen); m_memDC.SelectStockObject(NULL_BRUSH); m_memDC.Rectangle(selRect); m_memDC.SelectObject(pOldPen); pen.DeleteObject(); } } else if (m_selectionMode == SELECT_FREE_FORM && !m_freeFormPoints.empty()) { //转换为屏幕坐标数组 CPoint* screenPoints = new CPoint[m_freeFormPoints.size()]; for (size_t i = 0; i < m_freeFormPoints.size(); ++i) { screenPoints[i] = ConvertToScreenPoint(m_freeFormPoints[i]); } // 绘制路径 CPen pen(PS_SOLID, 1, m_bFreeFormSelecting ? RGB(255, 0, 0) : RGB(0, 255, 0)); CPen* pOldPen = m_memDC.SelectObject(&pen); m_memDC.SelectStockObject(NULL_BRUSH); // 使用Polyline绘制连续线条 m_memDC.Polyline(screenPoints, (int)m_freeFormPoints.size()); // 如果是闭合路径,绘制填充区域 if (!m_bFreeFormSelecting && m_freeFormPoints.size() > 2) { // 绘制闭合提示标记 CRect markRect(screenPoints[0].x - 3, screenPoints[0].y - 3, screenPoints[0].x + 3, screenPoints[0].y + 3); CBrush markBrush(RGB(255, 255, 0)); m_memDC.FillRect(&markRect, &markBrush); } m_memDC.SelectObject(pOldPen); pen.DeleteObject(); delete[] screenPoints; } } //当用户拖动最小化窗口时系统调用此函数取得光标 //显示。 HCURSOR CMyPS2Dlg::OnQueryDragIcon() { return static_cast(m_hIcon); } //打开 void CMyPS2Dlg::OnBnClickedButton2() { if (!m_layer1.image.IsNull()) { UINT i; i = MessageBox(_T(“确认重新打开图片吗?”), _T(“提示”), MB_YESNO | MB_ICONQUESTION); if (i != IDYES) { return; } } CFileDialog dlg(TRUE, _T(“.bmp;.jpg;.png"), NULL, OFN_FILEMUSTEXIST, _T("Image Files|.bmp;.jpg;.png||”), this); if (dlg.DoModal() == IDOK) { // 释放旧资源 m_layer1.history.clear(); m_layer1.currentHistoryIndex = -1; m_layer1.isSelected = true; if (!m_layer1.image.IsNull()) { m_layer1.image.Destroy(); } if (!m_layer1.displayImage.IsNull()) { m_layer1.displayImage.Destroy(); } if (m_layer1.image.Load(dlg.GetPathName()) != S_OK) { AfxMessageBox(L"图像加载失败!\n请检查格式支持(BMP/JPG/PNG)"); return; } else { // 加载新图像 ImageState initialState; initialState.brightness = 0; initialState.saturation = 1.0f; initialState.mosaic = 1; initialState.alpha = 1.0f; if (!m_layer1.image.IsNull()) { if (!initialState.image.IsNull()) { initialState.image.Destroy(); } initialState.image.Create(m_layer1.image.GetWidth(), m_layer1.image.GetHeight(), m_layer1.image.GetBPP()); CDC* pSrcDC = CDC::FromHandle(m_layer1.image.GetDC()); CDC* pDstDC = CDC::FromHandle(initialState.image.GetDC()); pDstDC->BitBlt(0, 0, m_layer1.image.GetWidth(), m_layer1.image.GetHeight(), pSrcDC, 0, 0, SRCCOPY); m_layer1.image.ReleaseDC(); initialState.image.ReleaseDC(); } m_layer1.history.push_back(initialState); m_layer1.history.push_back(initialState); m_layer1.currentHistoryIndex = 1; // 重置所有参数 m_nlightValue = 0; m_nsatureValue = 1.0f; m_nmskValue = 1; m_layer1.alpha = 1.0f; // 重置底层透明度为不透明 m_layer2.alpha = 0.5f; // 重置顶层透明度为半透明 // 初始化UI控件 litslider.SetPos(100); // 假设滑块范围0-200,100对应亮度0 saturslider.SetPos(100); // 假设滑块范围0-200,100对应饱度1.0 mskslider.SetPos(1); // 马赛克块大小(1~20) m_sliderLay1.SetPos(100); // 新增:底层透明度滑块(0-100) m_sliderLay2.SetPos(50); // 新增:顶层透明度滑块(0-100) // 生成显示图像 UpdateDisplayImage(m_layer1); } } } //保存 void CMyPS2Dlg::OnBnClickedButton3() { CFileDialog dlg(FALSE, _T(“.jpg"), _T(“output.jpg”), OFN_OVERWRITEPROMPT, _T("JPEG Files|.jpg||”), this); if (dlg.DoModal() == IDOK) { if (m_layer1.isSelected) { if (m_layer1.displayImage.IsNull()) { // 改为检查 m_displayImage AfxMessageBox(_T("请先打开图片!")); return; } if (m_layer1.currentHistoryIndex < 0) { AfxMessageBox(_T("图片失效")); return; } else { m_layer1.displayImage.Save(dlg.GetPathName()); } } // 保存处理后的图像 else { if (m_layer2.displayImage.IsNull()) { // 改为检查 m_displayImage AfxMessageBox(_T("请先打开图片!")); return; } if (m_layer2.currentHistoryIndex < 0) { AfxMessageBox(_T("图片失效")); return; } else { m_layer2.displayImage.Save(dlg.GetPathName()); } } } // TODO: 在此添加控件通知处理程序代码 } //退出 void CMyPS2Dlg::OnBnClickedButton4() { UINT i; i = MessageBox(_T(“请确认图片保存再退出。”), _T(“提示”), MB_YESNO | MB_ICONQUESTION); if (i == IDYES) { exit(0); } // TODO: 在此添加控件通知处理程序代码 } //亮度滑块 void CMyPS2Dlg::OnNMCustomdrawSliderlit(NMHDR* pNMHDR, LRESULT* pResult) { LPNMCUSTOMDRAW pNMCD = reinterpret_cast(pNMHDR); *pResult = 0; } //亮度编辑框 void CMyPS2Dlg::OnEnChangeEditlit() { if (m_bStateDirty) return; CString strValue; litedit.GetWindowText(strValue); int brightness = _ttoi(strValue)+100; // 检查输入值是否在有效范围内 (-100 到 100) brightness = max(0, min(200, brightness)); litslider.SetPos(brightness); // 应用亮度调整 OnParameterChanged(); // TODO: 如果该控件是 RICHEDIT 控件,它将不 // 发送此通知,除非重写 CDialogEx::OnInitDialog() // 函数并调用 CRichEditCtrl().SetEventMask(), // 同时将 ENM_CHANGE 标志“或”运算到掩码中。 // TODO: 在此添加控件通知处理程序代码 } void CMyPS2Dlg::ApplyBrightnessToPixels(BYTE* pBits, int width, int height, int pitch, int channels, int brightness) { for (int y = 0; y < height; y++) { BYTE* pRow = pBits + y * pitch; for (int x = 0; x < width; x++) { for (int c = 0; c < 3; c++) // 处理BGR通道 { int newVal = pRow[x * channels + c] + brightness; pRow[x * channels + c] = (BYTE)min(255, max(0, newVal)); } } } } void CMyPS2Dlg::ApplySaturationToPixels(BYTE* pBits, int width, int height, int pitch, int channels, float saturation) { // 确保饱度范围合理(0.0~3.0) saturation = min(max(saturation, 0.0f), 2.0f); for (int y = 0; y < height; y++) { BYTE* pRow = pBits + y * pitch; for (int x = 0; x < width; x++) { BYTE& b = pRow[x * channels]; BYTE& g = pRow[x * channels + 1]; BYTE& r = pRow[x * channels + 2]; // 计算灰度值(更精确的权重) float gray = 0.299f * r + 0.587f * g + 0.114f * b; // 调整饱度(非线性插值,避免过度失真) float blendFactor = saturation ; r = (BYTE)min(255.0f, max(0.0f, gray + blendFactor * (r - gray))); g = (BYTE)min(255.0f, max(0.0f, gray + blendFactor * (g - gray))); b = (BYTE)min(255.0f, max(0.0f, gray + blendFactor * (b - gray))); } } } void CMyPS2Dlg::ApplyMosaicToPixels(BYTE* pBits, int width, int height, int pitch, int channels, int blockSize) { for (int y = 0; y < height; y += blockSize) { for (int x = 0; x < width; x += blockSize) { // 计算当前块的边界 int blockEndX = min(x + blockSize, width); int blockEndY = min(y + blockSize, height); // 计算块内像素的平均颜色 long sumR = 0, sumG = 0, sumB = 0; int count = 0; for (int by = y; by < blockEndY; by++) { BYTE* pRow = pBits + by * pitch; for (int bx = x; bx < blockEndX; bx++) { sumB += pRow[bx * channels]; sumG += pRow[bx * channels + 1]; sumR += pRow[bx * channels + 2]; count++; } } BYTE avgR = (BYTE)(sumR / count); BYTE avgG = (BYTE)(sumG / count); BYTE avgB = (BYTE)(sumB / count); // 将整个块设为平均颜色 for (int by = y; by < blockEndY; by++) { BYTE* pRow = pBits + by * pitch; for (int bx = x; bx < blockEndX; bx++) { pRow[bx * channels] = avgB; pRow[bx * channels + 1] = avgG; pRow[bx * channels + 2] = avgR; } } } } } void CMyPS2Dlg::OnNMCustomdrawSlidersatur(NMHDR* pNMHDR, LRESULT* pResult) { LPNMCUSTOMDRAW pNMCD = reinterpret_cast(pNMHDR); // TODO: 在此添加控件通知处理程序代码 *pResult = 0; } //饱度编辑框 void CMyPS2Dlg::OnEnChangeEditsatur() { if (m_bStateDirty) return; CString strValue; saturedit.GetWindowText(strValue); float sat = _ttof(strValue)*100.0f+100.0f; // 限制范围并同步滑块 sat = max(0.0f, min(200.0f, sat)); saturslider.SetPos((int)sat); // 统一计算为浮点数(0.0~2.0) m_nsatureValue = sat / 100.0f; // 新增此行 OnParameterChanged(); // TODO: 如果该控件是 RICHEDIT 控件,它将不 // 发送此通知,除非重写 CDialogEx::OnInitDialog() // 函数并调用 CRichEditCtrl().SetEventMask(), // 同时将 ENM_CHANGE 标志“或”运算到掩码中。 // TODO: 在此添加控件通知处理程序代码 } void CMyPS2Dlg::OnNMCustomdrawSlidermsk(NMHDR* pNMHDR, LRESULT* pResult) { LPNMCUSTOMDRAW pNMCD = reinterpret_cast(pNMHDR); // TODO: 在此添加控件通知处理程序代码 *pResult = 0; } //马赛克编辑框 void CMyPS2Dlg::OnEnChangeEditmsk() { if (m_bStateDirty) return; CString strValue; mskedit.GetWindowText(strValue); int size = _ttoi(strValue); // 限制范围并同步滑块 size = max(1, min(50, size)); mskslider.SetPos(size); // 应用马赛克效果 OnParameterChanged(); // TODO: 如果该控件是 RICHEDIT 控件,它将不 // 发送此通知,除非重写 CDialogEx::OnInitDialog() // 函数并调用 CRichEditCtrl().SetEventMask(), // 同时将 ENM_CHANGE 标志“或”运算到掩码中。 // TODO: 在此添加控件通知处理程序代码 } //滑块 void CMyPS2Dlg::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) { if (m_bStateDirty)return; int id = pScrollBar->GetDlgCtrlID(); if (id == IDC_SLIDERLIT) { // 亮度滑块 m_nlightValue = litslider.GetPos() - 100; // 范围:-100 ~ +100 CString strValue; strValue.Format(_T("%d"), m_nlightValue); litedit.SetWindowText(strValue); } else if (id == IDC_SLIDERSATUR) { // 饱度滑块 m_nsatureValue = (saturslider.GetPos()) / 100.0f; // 范围:0.0 ~ 2.0 float sat = m_nsatureValue - 1.0f; CString strValue; strValue.Format(_T("%.1f"), sat); saturedit.SetWindowText(strValue); //UpdateDisplayImage(); } else if (id == IDC_SLIDERMSK) { // 马赛克滑块 m_nmskValue = mskslider.GetPos(); // 范围:1 ~ 50 CString strValue; strValue.Format(_T("%d"), m_nmskValue); mskedit.SetWindowText(strValue); //UpdateDisplayImage(); } else if (id == IDC_SLIDERL1) { m_layer1.alpha = (float)m_sliderLay1.GetPos() / 100.0f; // 范围:0.0 ~ 1.0 InvalidateRect(GetImageClientRect(m_layer1.image)); // 重绘图片区域 } // 顶层图片透明度滑块 else if (id == IDC_SLIDERL2) { m_layer2.alpha = (float)m_sliderLay2.GetPos() / 100.0f; // 范围:0.0 ~ 1.0 InvalidateRect(m_overlayRect); // 只重绘叠加层区域 } OnParameterChanged(); CDialogEx::OnHScroll(nSBCode, nPos, pScrollBar); } void CMyPS2Dlg::OnBnClickedButtonReset() { //if (!m_originalImage.IsNull()) { // m_nlightValue = 0; // m_nsatureValue = 0.0f; // m_nmskValue = 1; // litslider.SetPos(50); // saturslider.SetPos(50); // litslider.SetPos(1); // litedit.SetWindowText(_T("0")); // saturedit.SetWindowText(_T("0.0")); // mskedit.SetWindowText(_T("1")); // UpdateDisplayImage(); //} } //更新1 void CMyPS2Dlg::UpdateDisplayImage(ImageLayer& layer) { if (layer.currentHistoryIndex < 0) return; if(layer.image.IsNull()) return; if (layer.displayImage.IsNull() || layer.displayImage.GetWidth() != layer.image.GetWidth() || layer.displayImage.GetHeight() != layer.image.GetHeight()) { layer.displayImage.Destroy(); layer.displayImage.Create(layer.image.GetWidth(), layer.image.GetHeight(), layer.image.GetBPP()); } // 复制原图到显示图像 CDC* pSrcDC = CDC::FromHandle(layer.image.GetDC()); CDC* pDstDC = CDC::FromHandle(layer.displayImage.GetDC()); pDstDC->BitBlt(0, 0, layer.image.GetWidth(), layer.image.GetHeight(), pSrcDC, 0, 0, SRCCOPY); layer.image.ReleaseDC(); layer.displayImage.ReleaseDC(); // 应用当前参数效果 BYTE* pBits = (BYTE*)layer.displayImage.GetBits(); if (!pBits) return; int pitch = layer.displayImage.GetPitch(); int width = layer.displayImage.GetWidth(); int height = layer.displayImage.GetHeight(); int bpp = layer.displayImage.GetBPP(); int channels = (bpp == 32) ? 4 : 3; if (select) { if (layer.history[layer.currentHistoryIndex].mosaic > 1) { ApplyMosaicToPixels(pBits, width, height, pitch, channels, layer.history[layer.currentHistoryIndex].mosaic); } if (layer.history[layer.currentHistoryIndex].brightness != 0) { ApplyBrightnessToPixels(pBits, width, height, pitch, channels, layer.history[layer.currentHistoryIndex].brightness); } if (layer.history[layer.currentHistoryIndex].saturation != 1.0f) { ApplySaturationToPixels(pBits, width, height, pitch, channels, layer.history[layer.currentHistoryIndex].saturation); } ApplyAdvancedEffectsToSelection(m_nlightValue, m_nsatureValue, m_isBlackWhite, m_isSepia, m_nmskValue, layer); } else { // 全局应用效果 if (m_nmskValue > 1) { ApplyMosaicToPixels(pBits, width, height, pitch, channels, m_nmskValue); } if (m_nlightValue != 0) { ApplyBrightnessToPixels(pBits, width, height, pitch, channels, m_nlightValue); } if (m_nsatureValue != 1.0f) { ApplySaturationToPixels(pBits, width, height, pitch, channels, m_nsatureValue); } if (m_isBlackWhite) ApplyBlackWhiteToPixels(pBits, width, height, pitch, channels); else if (m_isSepia) ApplySepiaToPixels(pBits, width, height, pitch, channels); } InvalidateRect(NULL, FALSE); UpdateWindow(); } //黑白 void CMyPS2Dlg::ApplyBlackWhiteToPixels(BYTE* pBits, int width, int height, int pitch, int channels) { for (int y = 0; y < height; y++) { BYTE* pRow = pBits + y * pitch; for (int x = 0; x < width; x++) { BYTE& b = pRow[x * channels]; BYTE& g = pRow[x * channels + 1]; BYTE& r = pRow[x * channels + 2]; // 计算灰度值(加权平均) BYTE gray = (BYTE)(0.299f * r + 0.587f * g + 0.114f * b); // 所有通道设为灰度值 b = g = r = gray; } } } //怀旧 void CMyPS2Dlg::ApplySepiaToPixels(BYTE* pBits, int width, int height, int pitch, int channels) { for (int y = 0; y < height; y++) { BYTE* pRow = pBits + y * pitch; for (int x = 0; x < width; x++) { BYTE& b = pRow[x * channels]; BYTE& g = pRow[x * channels + 1]; BYTE& r = pRow[x * channels + 2]; // 怀旧色计算公式 int newR = min(255, (int)(0.393f * r + 0.769f * g + 0.189f * b)); int newG = min(255, (int)(0.349f * r + 0.686f * g + 0.168f * b)); int newB = min(255, (int)(0.272f * r + 0.534f * g + 0.131f * b)); r = (BYTE)newR; g = (BYTE)newG; b = (BYTE)newB; } } } //定时器 void CMyPS2Dlg::OnTimer(UINT_PTR nIDEvent) { if (nIDEvent == SAVE_DELAY_TIMER) { KillTimer(m_nSaveTimer); m_nSaveTimer = 0; if (m_bStateDirty) { if (m_layer1.isSelected) { SaveCurrentState(m_layer1); } else { SaveCurrentState(m_layer2); } m_bStateDirty = false; } } CDialogEx::OnTimer(nIDEvent); } //参数变化 void CMyPS2Dlg::OnParameterChanged() { ImageLayer& activeLayer = m_layer1.isSelected ? m_layer1 : m_layer2; // 更新当前参数值 m_nlightValue = litslider.GetPos() - 100; m_nsatureValue = (saturslider.GetPos()) / 100.0f; m_nmskValue = mskslider.GetPos(); // 标记状态已改变 m_bStateDirty = true; // 重置保存定时器 if (m_nSaveTimer) { KillTimer(m_nSaveTimer); } m_nSaveTimer = SetTimer(SAVE_DELAY_TIMER, SAVE_DELAY, NULL); // 立即更新显示 if (m_layer1.isSelected) { UpdateDisplayImage(m_layer1); } else { UpdateDisplayImage(m_layer2); } } //新增状态 void CMyPS2Dlg::SaveCurrentState(ImageLayer& layer) { if (!m_bStateDirty) return; if (layer.currentHistoryIndex < 0) return; if (select) { return; } ImageState currentState; if (layer.modified) { currentState.brightness = layer.history[layer.currentHistoryIndex].brightness; currentState.saturation = layer.history[layer.currentHistoryIndex].saturation; currentState.mosaic = layer.history[layer.currentHistoryIndex].mosaic; currentState.alpha = layer.history[layer.currentHistoryIndex].alpha; } else { currentState.brightness = m_nlightValue; currentState.saturation = m_nsatureValue; currentState.mosaic = m_nmskValue; currentState.alpha = layer.alpha; } if (!layer.image.IsNull()) { if (!currentState.image.IsNull()) { currentState.image.Destroy(); } currentState.image.Create(layer.image.GetWidth(), layer.image.GetHeight(), layer.image.GetBPP()); CDC* pSrcDC = CDC::FromHandle(layer.image.GetDC()); CDC* pDstDC = CDC::FromHandle(currentState.image.GetDC()); pDstDC->BitBlt(0, 0, layer.image.GetWidth(), layer.image.GetHeight(), pSrcDC, 0, 0, SRCCOPY); layer.image.ReleaseDC(); currentState.image.ReleaseDC(); } if (layer.currentHistoryIndex >= 0 && layer.history[layer.currentHistoryIndex] == currentState&&(!layer.modified)&&(!doodend)) { return; } for (int i = layer.currentHistoryIndex +1; i <= layer.history.size() - 1; i++) { layer.history.erase(layer.history.begin() + i); } layer.history.push_back(currentState); layer.currentHistoryIndex +=1; layer.modified = false; doodend = false; // 限制历史记录数量 const int MAX_HISTORY = 40; if (layer.history.size() > MAX_HISTORY) { layer.history.erase(layer.history.begin()); layer.currentHistoryIndex--; } m_bStateDirty = false; } //销毁 void CMyPS2Dlg::OnDestroy() { CDialogEx::OnDestroy(); // 调用基类实现 // 清理定时器资源 if (m_nSaveTimer != 0) { KillTimer(m_nSaveTimer); m_nSaveTimer = 0; } // 清理图像资源 if (!m_layer1.image.IsNull()) m_layer1.image.Destroy(); if (!m_layer2.image.IsNull()) m_layer2.image.Destroy(); if (!m_layer1.displayImage.IsNull()) m_layer1.displayImage.Destroy(); if (!m_layer2.displayImage.IsNull()) m_layer2.displayImage.Destroy(); if (!m_doodleTempImage.IsNull()) m_doodleTempImage.Destroy(); //GdiplusShutdown(m_gdiplusToken); CDialogEx::OnDestroy(); } //撤回 void CMyPS2Dlg::OnUndo() { if (m_layer1.isSelected) { if (m_layer1.currentHistoryIndex > 0) { m_layer1.currentHistoryIndex–; ApplyHistoryState(m_layer1.currentHistoryIndex,m_layer1); } else { AfxMessageBox(_T(“不可撤回。”)); } } else { if (m_layer2.currentHistoryIndex > 0) { m_layer2.currentHistoryIndex–; ApplyHistoryState(m_layer2.currentHistoryIndex, m_layer2); } else { AfxMessageBox(_T(“不可撤回。”)); } } } //重做 void CMyPS2Dlg::OnRedo() { if (m_layer1.isSelected) { if (m_layer1.currentHistoryIndex < static_cast(m_layer1.history.size()) - 1) { m_layer1.currentHistoryIndex++; ApplyHistoryState(m_layer1.currentHistoryIndex,m_layer1); } else { AfxMessageBox(_T(“不可重做。”)); } } else { if (m_layer2.currentHistoryIndex < static_cast(m_layer2.history.size()) - 1) { m_layer2.currentHistoryIndex++; ApplyHistoryState(m_layer2.currentHistoryIndex, m_layer2); } else { AfxMessageBox(_T(“不可重做。”)); } } } void CMyPS2Dlg::ApplyHistoryState(int index, ImageLayer& layer) { if (index < 0 || index >= static_cast(layer.history.size())) return; const ImageState& state = layer.history[index]; if (!state.image.IsNull()) { if (!layer.image.IsNull()) { layer.image.Destroy(); } layer.image.Create(state.image.GetWidth(), state.image.GetHeight(), state.image.GetBPP()); CDC* pSrcDC = CDC::FromHandle(state.image.GetDC()); CDC* pDstDC = CDC::FromHandle(layer.image.GetDC()); pDstDC->BitBlt(0, 0, state.image.GetWidth(), state.image.GetHeight(), pSrcDC, 0, 0, SRCCOPY); state.image.ReleaseDC(); layer.image.ReleaseDC(); } // 更新UI控件 litslider.SetPos(state.brightness + 100); saturslider.SetPos((int)(state.saturation * 100.0f)); mskslider.SetPos(state.mosaic); if (m_layer1.isSelected) { m_sliderLay1.SetPos((int)(state.alpha * 100.0f)); } else { m_sliderLay2.SetPos((int)(state.alpha * 100.0f)); } CString str; str.Format(_T("%d"), state.brightness); litedit.SetWindowText(str); str.Format(_T("%.1f"), state.saturation); saturedit.SetWindowText(str); str.Format(_T("%d"), state.mosaic); mskedit.SetWindowText(str); // 更新当前参数 m_nlightValue = state.brightness; m_nsatureValue = state.saturation; m_nmskValue = state.mosaic; layer.alpha = state.alpha; // 更新显示 UpdateDisplayImage(layer); } //撤回 void CMyPS2Dlg::OnBnClickedButton1() { OnUndo(); // TODO: 在此添加控件通知处理程序代码 } void CMyPS2Dlg::OnBnClickedButton5() { OnRedo(); // TODO: 在此添加控件通知处理程序代码 } //黑白滤镜 void CMyPS2Dlg::OnBnClickedButton6() { m_isBlackWhite = !m_isBlackWhite; m_isSepia = false; // 确保二者互斥 if (m_layer1.isSelected) { UpdateDisplayImage(m_layer1); } else { UpdateDisplayImage(m_layer2); } // TODO: 在此添加控件通知处理程序代码 } //怀旧滤镜 void CMyPS2Dlg::OnBnClickedButton7() { m_isSepia = !m_isSepia; m_isBlackWhite = false; // 确保二者互斥 if (m_layer1.isSelected) { UpdateDisplayImage(m_layer1); } else { UpdateDisplayImage(m_layer2); } // TODO: 在此添加控件通知处理程序代码 } //退出选区 void CMyPS2Dlg::OnBnClickedButton8() { ImageLayer& activeLayer = m_layer1.isSelected ? m_layer1 : m_layer2; if (activeLayer.clonedRegion.active && activeLayer.clonedRegion.visible) { // 将克隆区域绘制到目标位置 CDC* pDstDC = CDC::FromHandle(activeLayer.image.GetDC()); CDC* pSrcDC = CDC::FromHandle(activeLayer.clonedRegion.image.GetDC()); pDstDC->BitBlt( activeLayer.clonedRegion.destRect.left, activeLayer.clonedRegion.destRect.top, activeLayer.clonedRegion.destRect.Width(), activeLayer.clonedRegion.destRect.Height(), pSrcDC, 0, 0, SRCCOPY); activeLayer.image.ReleaseDC(); activeLayer.clonedRegion.image.ReleaseDC(); } // 重置克隆区域 activeLayer.clonedRegion.active = false; activeLayer.clonedRegion.visible = false; select = false; if (m_layer1.isSelected) { if (HasSelection() && !m_layer1.displayImage.IsNull() && !m_layer1.image.IsNull()) { CRect validRect; if (m_selectionMode == SELECT_RECTANGLE) { validRect = m_rcSelection; validRect.IntersectRect(validRect, CRect(0, 0, m_layer1.image.GetWidth(), m_layer1.image.GetHeight())); } else if (m_selectionMode == SELECT_FREE_FORM && m_rgnFreeForm.GetSafeHandle()) { m_rgnFreeForm.GetRgnBox(&validRect); validRect.IntersectRect(validRect, CRect(0, 0, m_layer1.image.GetWidth(), m_layer1.image.GetHeight())); } if (!validRect.IsRectEmpty()) { // 只复制选区内的修改回原图 CDC* pDispDC = CDC::FromHandle(m_layer1.displayImage.GetDC()); CDC* pOrigDC = CDC::FromHandle(m_layer1.image.GetDC()); // 设置裁剪区域(只复制选区内的像素) if (m_selectionMode == SELECT_FREE_FORM) { pOrigDC->SelectClipRgn(&m_rgnFreeForm); } pOrigDC->BitBlt( validRect.left, validRect.top, validRect.Width(), validRect.Height(), pDispDC, validRect.left, validRect.top, SRCCOPY); // 重置裁剪区域 pOrigDC->SelectClipRgn(NULL); m_layer1.image.ReleaseDC(); m_layer1.displayImage.ReleaseDC(); // 保存当前状态到历史记录 m_layer1.modified = true; m_bStateDirty = true; m_nlightValue = m_layer1.history[m_layer1.currentHistoryIndex].brightness; m_nsatureValue = m_layer1.history[m_layer1.currentHistoryIndex].saturation; m_nmskValue = m_layer1.history[m_layer1.currentHistoryIndex].mosaic; SaveCurrentState(m_layer1); } } } else { if (HasSelection() && !m_layer2.displayImage.IsNull() && !m_layer2.image.IsNull()) { CRect validRect; if (m_selectionMode == SELECT_RECTANGLE) { validRect = m_rcSelection; validRect.IntersectRect(validRect, CRect(0, 0, m_layer2.image.GetWidth(), m_layer2.image.GetHeight())); } else if (m_selectionMode == SELECT_FREE_FORM && m_rgnFreeForm.GetSafeHandle()) { m_rgnFreeForm.GetRgnBox(&validRect); validRect.IntersectRect(validRect, CRect(0, 0, m_layer2.image.GetWidth(), m_layer2.image.GetHeight())); } if (!validRect.IsRectEmpty()) { // 只复制选区内的修改回原图 CDC* pDispDC = CDC::FromHandle(m_layer2.displayImage.GetDC()); CDC* pOrigDC = CDC::FromHandle(m_layer2.image.GetDC()); // 设置裁剪区域(只复制选区内的像素) if (m_selectionMode == SELECT_FREE_FORM) { pOrigDC->SelectClipRgn(&m_rgnFreeForm); } pOrigDC->BitBlt( validRect.left, validRect.top, validRect.Width(), validRect.Height(), pDispDC, validRect.left, validRect.top, SRCCOPY); // 重置裁剪区域 pOrigDC->SelectClipRgn(NULL); m_layer2.image.ReleaseDC(); m_layer2.displayImage.ReleaseDC(); // 保存当前状态到历史记录 m_layer2.modified = true; m_bStateDirty = true; m_nlightValue = m_layer2.history[m_layer2.currentHistoryIndex].brightness; m_nsatureValue = m_layer2.history[m_layer2.currentHistoryIndex].saturation; m_nmskValue = m_layer2.history[m_layer2.currentHistoryIndex].mosaic; SaveCurrentState(m_layer2); } } } /*m_bStateDirty = true;*/ litslider.SetPos(m_nlightValue); saturslider.SetPos((int)(m_nsatureValue * 100.0f)); mskslider.SetPos(m_nmskValue); CString strValue; strValue.Format(_T("%d"), m_nlightValue); litedit.SetWindowText(strValue); strValue.Format(_T("%.1f"), m_nsatureValue); saturedit.SetWindowText(strValue); strValue.Format(_T("%d"), m_nmskValue); mskedit.SetWindowText(strValue); m_rcSelection.SetRectEmpty(); m_ptStart = m_ptEnd = CPoint(0, 0); if (m_rgnFreeForm.GetSafeHandle()) { // 2. 清除不规则选区数据 m_rgnFreeForm.DeleteObject(); // 删除区域对象 } m_freeFormPoints.clear(); // 清空点集 m_bSelecting = false;//// 3. 重置状态标志 m_bFreeFormSelecting = false; InvalidateRect(NULL, FALSE); UpdateWindow(); // TODO: 在此添加控件通知处理程序代码 } CRect CMyPS2Dlg::GetImageClientRect(const CImage& image) { CRect ctrlRect; m_staticImage.GetWindowRect(&ctrlRect); ScreenToClient(&ctrlRect); int imgW = image.GetWidth(); int imgH = image.GetHeight(); double ratio = min( (double)ctrlRect.Width() / imgW, (double)ctrlRect.Height() / imgH ); int drawW = (int)(imgW * ratio); int drawH = (int)(imgH * ratio); int x = ctrlRect.left + (ctrlRect.Width() - drawW) / 2; int y = ctrlRect.top + (ctrlRect.Height() - drawH) / 2; return CRect(x, y, x + drawW, y + drawH); } std::unique_ptrGdiplus::Bitmap CMyPS2Dlg::CImageToGdiPlusBitmap(CImage& image) { if (image.IsNull()) return nullptr; // 直接通过HBITMAP转换 return std::unique_ptr<Gdiplus::Bitmap>( Gdiplus::Bitmap::FromHBITMAP( (HBITMAP)image, // CImage可隐式转换为HBITMAP NULL // 不使用调色板 ) ); } void CMyPS2Dlg::OnLButtonDown(UINT nFlags, CPoint point) { ImageLayer& activeLayer = m_layer1.isSelected ? m_layer1 : m_layer2; // 检查是否点击在克隆区域上 if (activeLayer.clonedRegion.active && activeLayer.clonedRegion.visible) { CRect screenRect = ConvertToScreenRect(activeLayer.clonedRegion.destRect); if (screenRect.PtInRect(point)) { // 记录拖动起始点 m_ptDragStart = point; m_ptCloneStart = activeLayer.clonedRegion.destRect.TopLeft(); m_bDragging = true; SetCapture(); // 捕获鼠标 TRACE(_T("开始拖动克隆区域\n")); TRACE(_T("原始位置: (%d, %d)\n"), m_ptCloneStart.x, m_ptCloneStart.y); TRACE(_T("屏幕位置: (%d, %d)\n"), point.x, point.y); return; // 不处理其他逻辑 } } if (m_bDoodleMode) { CRect imgRect = GetImageClientRect(m_layer1.isSelected?m_layer1.image:m_layer2.image); if (imgRect.PtInRect(point)) { // 转换为图像坐标 CPoint imgPoint; imgPoint.x = (point.x - imgRect.left) * m_doodleTempImage.GetWidth() / imgRect.Width(); imgPoint.y = (point.y - imgRect.top) * m_doodleTempImage.GetHeight() / imgRect.Height(); m_ptDoodleStart = imgPoint; m_bDoodling = true; } return; // 涂鸦模式下不进行其他选择操作 } if (m_layer1.isSelected) { CRect imgRect = GetImageClientRect(m_layer1.image); if (imgRect.PtInRect(point)) { if (m_selectionMode == SELECT_RECTANGLE) { // 原有矩形选区代码 m_ptStart.x = (point.x - imgRect.left) * m_layer1.displayImage.GetWidth() / imgRect.Width(); m_ptStart.y = (point.y - imgRect.top) * m_layer1.displayImage.GetHeight() / imgRect.Height(); m_ptEnd = m_ptStart; m_bSelecting = true; SetCapture(); } else if (m_selectionMode == SELECT_FREE_FORM) { m_bFreeFormSelecting = true; m_freeFormPoints.clear(); // 转换为图像坐标存储 CPoint imgPoint; imgPoint.x = (point.x - imgRect.left) * m_layer1.displayImage.GetWidth() / imgRect.Width(); imgPoint.y = (point.y - imgRect.top) * m_layer1.displayImage.GetHeight() / imgRect.Height(); m_freeFormPoints.push_back(imgPoint); SetCapture(); Invalidate(); } } } else { CRect imgRect = GetImageClientRect(m_layer2.image); if (imgRect.PtInRect(point)) { if (m_selectionMode == SELECT_RECTANGLE) { // 原有矩形选区代码 m_ptStart.x = (point.x - imgRect.left) * m_layer2.displayImage.GetWidth() / imgRect.Width(); m_ptStart.y = (point.y - imgRect.top) * m_layer2.displayImage.GetHeight() / imgRect.Height(); m_ptEnd = m_ptStart; m_bSelecting = true; SetCapture(); } else if (m_selectionMode == SELECT_FREE_FORM) { m_bFreeFormSelecting = true; m_freeFormPoints.clear(); // 转换为图像坐标存储 CPoint imgPoint; imgPoint.x = (point.x - imgRect.left) * m_layer2.displayImage.GetWidth() / imgRect.Width(); imgPoint.y = (point.y - imgRect.top) * m_layer2.displayImage.GetHeight() / imgRect.Height(); m_freeFormPoints.push_back(imgPoint); SetCapture(); Invalidate(); } } } select = false; CDialogEx::OnLButtonDown(nFlags, point); } void CMyPS2Dlg::OnMouseMove(UINT nFlags, CPoint point) { #ifdef _DEBUG if (m_nDebugCounter++ % 10 == 0) // 每10次移动输出一次 { TRACE(_T(“鼠标位置: (%d, %d)\n”), point.x, point.y); if (m_bDragging) { TRACE(_T(“正在拖动克隆区域\n”)); } else if (m_bSelecting) { TRACE(_T(“正在选区操作\n”)); } } #endif if (m_bDragging) { ImageLayer& activeLayer = m_layer1.isSelected ? m_layer1 : m_layer2; // 计算移动距离(转换为图像坐标) CRect imgRect = GetImageClientRect(activeLayer.image); double scaleX = (double)activeLayer.image.GetWidth() / imgRect.Width(); double scaleY = (double)activeLayer.image.GetHeight() / imgRect.Height(); int dx = static_cast<int>((point.x - m_ptDragStart.x) * scaleX); int dy = static_cast<int>((point.y - m_ptDragStart.y) * scaleY); // 更新克隆区域位置(限制在图像范围内) int newX = max(0, min(activeLayer.image.GetWidth() - activeLayer.clonedRegion.destRect.Width(), (int)m_ptCloneStart.x + dx)); int newY = max(0, min(activeLayer.image.GetHeight() - activeLayer.clonedRegion.destRect.Height(), (int)m_ptCloneStart.y + dy)); activeLayer.clonedRegion.destRect.MoveToXY(newX, newY); Invalidate(); // 刷新显示 return; } if (m_bDoodleMode && m_bDoodling) { CRect imgRect = GetImageClientRect(m_layer1.isSelected?m_layer1.image:m_layer2.image); if (imgRect.PtInRect(point)) { // 转换为图像坐标 CPoint imgPoint; imgPoint.x = (point.x - imgRect.left) * m_doodleTempImage.GetWidth() / imgRect.Width(); imgPoint.y = (point.y - imgRect.top) * m_doodleTempImage.GetHeight() / imgRect.Height(); // 绘制线段 DrawDoodleLine(m_ptDoodleStart, imgPoint); m_ptDoodleStart = imgPoint; // 刷新显示 Invalidate(FALSE); } return; } if (m_layer1.isSelected) { if (m_bSelecting && !m_layer1.displayImage.IsNull() && m_selectionMode == SELECT_RECTANGLE) { // 1. 获取图像显示区域 CRect imgRect = GetImageClientRect(m_layer1.image); // 2. 约束鼠标在图像范围内 point.x = max(imgRect.left, min(imgRect.right, point.x)); point.y = max(imgRect.top, min(imgRect.bottom, point.y)); // 3. 保存旧选区用于刷新 CRect oldSelRect = ConvertToScreenRect(m_rcSelection); // 4. 转换为图像坐标并更新选区 m_ptEnd.x = (point.x - imgRect.left) * m_layer1.displayImage.GetWidth() / imgRect.Width(); m_ptEnd.y = (point.y - imgRect.top) * m_layer1.displayImage.GetHeight() / imgRect.Height(); m_rcSelection = CRect( min(m_ptStart.x, m_ptEnd.x), min(m_ptStart.y, m_ptEnd.y), max(m_ptStart.x, m_ptEnd.x), max(m_ptStart.y, m_ptEnd.y) ); // 5. 计算需要刷新的区域(新旧选区合并) CRect newSelRect = ConvertToScreenRect(m_rcSelection); CRect invalidRect = oldSelRect | newSelRect; invalidRect.InflateRect(2, 2); // 扩大2像素避免残影 // 6. 使用临时DC绘制动态选区 CClientDC dc(this); CPen pen(PS_DOT, 1, RGB(255, 0, 0)); CPen* pOldPen = dc.SelectObject(&pen); dc.SelectStockObject(NULL_BRUSH); int oldROP = dc.SetROP2(R2_XORPEN); dc.Rectangle(newSelRect); // 使用已定义的 newSelRect dc.SetROP2(oldROP); dc.SelectObject(pOldPen); pen.DeleteObject(); // 6. 精准刷新 RedrawWindow(invalidRect, NULL, RDW_INVALIDATE | RDW_UPDATENOW | RDW_NOERASE); } else if (m_bFreeFormSelecting && !m_layer1.displayImage.IsNull()) { CRect imgRect = GetImageClientRect(m_layer1.image); if (imgRect.PtInRect(point)) { // 转换为图像坐标 CPoint imgPoint; imgPoint.x = (point.x - imgRect.left) * m_layer1.displayImage.GetWidth() / imgRect.Width(); imgPoint.y = (point.y - imgRect.top) * m_layer1.displayImage.GetHeight() / imgRect.Height(); // 检查是否闭合(当前点接近起始点) if (m_freeFormPoints.size() > 10) // 至少10个点才开始检测闭合 { const CPoint& firstPoint = m_freeFormPoints[0]; double distance = sqrt(pow(imgPoint.x - firstPoint.x, 2) + pow(imgPoint.y - firstPoint.y, 2)); // 如果距离小于10像素认为闭合 if (distance < 10.0) { // 自动闭合路径 m_freeFormPoints.push_back(firstPoint); // 创建多边形区域 if (m_rgnFreeForm.GetSafeHandle()) m_rgnFreeForm.DeleteObject(); m_rgnFreeForm.CreatePolygonRgn( m_freeFormPoints.data(), (int)m_freeFormPoints.size(), ALTERNATE); m_bFreeFormSelecting = false; ReleaseCapture(); Invalidate(); return; } } // 避免重复添加相近点 if (m_freeFormPoints.empty() || abs(imgPoint.x - m_freeFormPoints.back().x) > 2 || abs(imgPoint.y - m_freeFormPoints.back().y) > 2) { m_freeFormPoints.push_back(imgPoint); // 计算需要刷新的区域 CRect invalidRect; if (m_freeFormPoints.size() > 1) { CPoint prevScreen = ConvertToScreenPoint(m_freeFormPoints[m_freeFormPoints.size() - 2]); CPoint currScreen = ConvertToScreenPoint(imgPoint); invalidRect.SetRect( min(prevScreen.x, currScreen.x) - 2, min(prevScreen.y, currScreen.y) - 2, max(prevScreen.x, currScreen.x) + 2, max(prevScreen.y, currScreen.y) + 2 ); } // 智能刷新 if (m_freeFormPoints.size() <= 2) { InvalidateRect(imgRect); } else if (!invalidRect.IsRectEmpty()) { RedrawWindow(invalidRect, NULL, RDW_INVALIDATE | RDW_UPDATENOW); } } } } } else { if (m_bSelecting && !m_layer2.displayImage.IsNull() && m_selectionMode == SELECT_RECTANGLE) { // 1. 获取图像显示区域 CRect imgRect = GetImageClientRect(m_layer2.image); // 2. 约束鼠标在图像范围内 point.x = max(imgRect.left, min(imgRect.right, point.x)); point.y = max(imgRect.top, min(imgRect.bottom, point.y)); // 3. 保存旧选区用于刷新 CRect oldSelRect = ConvertToScreenRect(m_rcSelection); // 4. 转换为图像坐标并更新选区 m_ptEnd.x = (point.x - imgRect.left) * m_layer2.displayImage.GetWidth() / imgRect.Width(); m_ptEnd.y = (point.y - imgRect.top) * m_layer2.displayImage.GetHeight() / imgRect.Height(); m_rcSelection = CRect( min(m_ptStart.x, m_ptEnd.x), min(m_ptStart.y, m_ptEnd.y), max(m_ptStart.x, m_ptEnd.x), max(m_ptStart.y, m_ptEnd.y) ); // 5. 计算需要刷新的区域(新旧选区合并) CRect newSelRect = ConvertToScreenRect(m_rcSelection); CRect invalidRect = oldSelRect | newSelRect; invalidRect.InflateRect(2, 2); // 扩大2像素避免残影 // 6. 使用临时DC绘制动态选区 CClientDC dc(this); CPen pen(PS_DOT, 1, RGB(255, 0, 0)); CPen* pOldPen = dc.SelectObject(&pen); dc.SelectStockObject(NULL_BRUSH); int oldROP = dc.SetROP2(R2_XORPEN); dc.Rectangle(newSelRect); // 使用已定义的 newSelRect dc.SetROP2(oldROP); dc.SelectObject(pOldPen); pen.DeleteObject(); // 6. 精准刷新 RedrawWindow(invalidRect, NULL, RDW_INVALIDATE | RDW_UPDATENOW | RDW_NOERASE); } else if (m_bFreeFormSelecting && !m_layer2.displayImage.IsNull()) { CRect imgRect = GetImageClientRect(m_layer2.image); if (imgRect.PtInRect(point)) { // 转换为图像坐标 CPoint imgPoint; imgPoint.x = (point.x - imgRect.left) * m_layer2.displayImage.GetWidth() / imgRect.Width(); imgPoint.y = (point.y - imgRect.top) * m_layer2.displayImage.GetHeight() / imgRect.Height(); // 检查是否闭合(当前点接近起始点) if (m_freeFormPoints.size() > 10) // 至少10个点才开始检测闭合 { const CPoint& firstPoint = m_freeFormPoints[0]; double distance = sqrt(pow(imgPoint.x - firstPoint.x, 2) + pow(imgPoint.y - firstPoint.y, 2)); // 如果距离小于10像素认为闭合 if (distance < 10.0) { // 自动闭合路径 m_freeFormPoints.push_back(firstPoint); // 创建多边形区域 if (m_rgnFreeForm.GetSafeHandle()) m_rgnFreeForm.DeleteObject(); m_rgnFreeForm.CreatePolygonRgn( m_freeFormPoints.data(), (int)m_freeFormPoints.size(), ALTERNATE); m_bFreeFormSelecting = false; ReleaseCapture(); Invalidate(); return; } } // 避免重复添加相近点 if (m_freeFormPoints.empty() || abs(imgPoint.x - m_freeFormPoints.back().x) > 2 || abs(imgPoint.y - m_freeFormPoints.back().y) > 2) { m_freeFormPoints.push_back(imgPoint); // 计算需要刷新的区域 CRect invalidRect; if (m_freeFormPoints.size() > 1) { CPoint prevScreen = ConvertToScreenPoint(m_freeFormPoints[m_freeFormPoints.size() - 2]); CPoint currScreen = ConvertToScreenPoint(imgPoint); invalidRect.SetRect( min(prevScreen.x, currScreen.x) - 2, min(prevScreen.y, currScreen.y) - 2, max(prevScreen.x, currScreen.x) + 2, max(prevScreen.y, currScreen.y) + 2 ); } // 智能刷新 if (m_freeFormPoints.size() <= 2) { InvalidateRect(imgRect); } else if (!invalidRect.IsRectEmpty()) { RedrawWindow(invalidRect, NULL, RDW_INVALIDATE | RDW_UPDATENOW); } } } } } __super::OnMouseMove(nFlags, point); } void CMyPS2Dlg::OnLButtonUp(UINT nFlags, CPoint point) { if (m_bDragging) { m_bDragging = false; ReleaseCapture(); return; // 不处理其他逻辑 } if (m_bDoodleMode && m_bDoodling) { m_bDoodling = false; return; } if (m_layer1.isSelected) { if (m_bSelecting || m_bFreeFormSelecting) { if (m_selectionMode == SELECT_RECTANGLE) { // 原有矩形选区结束代码 m_bSelecting = false; } else if (m_bFreeFormSelecting && m_selectionMode == SELECT_FREE_FORM) { CRect imgRect = GetImageClientRect(m_layer1.image); if (imgRect.PtInRect(point)) { // 转换为图像坐标 CPoint imgPoint; imgPoint.x = (point.x - imgRect.left) * m_layer1.displayImage.GetWidth() / imgRect.Width(); imgPoint.y = (point.y - imgRect.top) * m_layer1.displayImage.GetHeight() / imgRect.Height(); // 确保至少3个点才闭合 if (m_freeFormPoints.size() > 2) { // 闭合路径:添加第一个点作为终点 m_freeFormPoints.push_back(m_freeFormPoints[0]); // 删除旧区域(如果存在) if (m_rgnFreeForm.GetSafeHandle()) m_rgnFreeForm.DeleteObject(); // 创建多边形区域 m_rgnFreeForm.CreatePolygonRgn( m_freeFormPoints.data(), (int)m_freeFormPoints.size(), ALTERNATE); TRACE(_T("创建多边形选区,点数: %d\n"), m_freeFormPoints.size()); } else { // 点数不足,清除选区 m_freeFormPoints.clear(); } } m_bFreeFormSelecting = false; } select = true; ReleaseCapture(); Invalidate(); } } else { if (m_bSelecting || m_bFreeFormSelecting) { if (m_selectionMode == SELECT_RECTANGLE) { // 原有矩形选区结束代码 m_bSelecting = false; select = true; } else if (m_bFreeFormSelecting && m_selectionMode == SELECT_FREE_FORM) { CRect imgRect = GetImageClientRect(m_layer2.image); if (imgRect.PtInRect(point)) { // 转换为图像坐标 CPoint imgPoint; imgPoint.x = (point.x - imgRect.left) * m_layer2.displayImage.GetWidth() / imgRect.Width(); imgPoint.y = (point.y - imgRect.top) * m_layer2.displayImage.GetHeight() / imgRect.Height(); // 确保至少3个点才闭合 if (m_freeFormPoints.size() > 2) { // 闭合路径:添加第一个点作为终点 m_freeFormPoints.push_back(m_freeFormPoints[0]); // 删除旧区域(如果存在) if (m_rgnFreeForm.GetSafeHandle()) m_rgnFreeForm.DeleteObject(); // 创建多边形区域 m_rgnFreeForm.CreatePolygonRgn( m_freeFormPoints.data(), (int)m_freeFormPoints.size(), ALTERNATE); TRACE(_T("创建多边形选区,点数: %d\n"), m_freeFormPoints.size()); } else { // 点数不足,清除选区 m_freeFormPoints.clear(); } } m_bFreeFormSelecting = false; select = true; } ReleaseCapture(); Invalidate(); } } CDialogEx::OnLButtonUp(nFlags, point); } void CMyPS2Dlg::ApplyAdvancedEffectsToSelection(int brightness, float saturation, bool bBlackWhite, bool bSepia, int mosaicSize, ImageLayer& layer) { if (layer.image.IsNull()) return; // 1. 准备选区数据 CRect validRect; bool hasSelection = false; if (m_selectionMode == SELECT_RECTANGLE && !m_rcSelection.IsRectNull()) { // 矩形选区 validRect.SetRect( max(0, (int)m_rcSelection.left), max(0, (int)m_rcSelection.top), min(layer.image.GetWidth(), (int)m_rcSelection.right), min(layer.image.GetHeight(), (int)m_rcSelection.bottom) ); hasSelection = true; } else if (m_selectionMode == SELECT_FREE_FORM && m_rgnFreeForm.GetSafeHandle()) { // 不规则选区 m_rgnFreeForm.GetRgnBox(&validRect); hasSelection = true; } if (!hasSelection) return; // 2. 准备目标图像 if (layer.displayImage.GetBits() == nullptr || layer.displayImage.GetWidth() != layer.image.GetWidth() || layer.displayImage.GetHeight() != layer.image.GetHeight()) { layer.displayImage.Destroy(); layer.displayImage.Create(layer.image.GetWidth(), layer.image.GetHeight(), layer.image.GetBPP()); } // 3. 获取像素数据 BYTE* pDest = (BYTE*)layer.displayImage.GetBits(); BYTE* pSrc = (BYTE*)layer.image.GetBits(); int destPitch = layer.displayImage.GetPitch(); int srcPitch = layer.image.GetPitch(); int channels = (layer.displayImage.GetBPP() == 32) ? 4 : 3; // 4. 处理选区像素(包含马赛克效果) #pragma omp parallel for for (int y = validRect.top; y < validRect.bottom; y++) { BYTE* pDestRow = pDest + y * destPitch; BYTE* pSrcRow = pSrc + y * srcPitch; for (int x = validRect.left; x < validRect.right; x++) { // 检查是否在选区内(不规则选区需要额外检查) bool inSelection = true; if (m_selectionMode == SELECT_FREE_FORM) { inSelection = m_rgnFreeForm.PtInRegion(x, y); } if (inSelection) { BYTE* pDestPixel = &pDest[y * destPitch + x * channels]; // 计算马赛克块的平均颜色(直接从原图获取) if (mosaicSize > 1) { int blockStartX = (x / mosaicSize) * mosaicSize; int blockStartY = (y / mosaicSize) * mosaicSize; int blockEndX = min(blockStartX + mosaicSize, (int)validRect.right); int blockEndY = min(blockStartY + mosaicSize, (int)validRect.bottom); long sumR = 0, sumG = 0, sumB = 0; int count = 0; for (int by = blockStartY; by < blockEndY; by++) { for (int bx = blockStartX; bx < blockEndX; bx++) { // 不规则选区需要检查马赛克块内每个点 if (m_selectionMode != SELECT_FREE_FORM || m_rgnFreeForm.PtInRegion(bx, by)) { BYTE* pSrcPixel = &pSrc[by * srcPitch + bx * channels]; sumB += pSrcPixel[0]; sumG += pSrcPixel[1]; sumR += pSrcPixel[2]; count++; } } } if (count > 0) { BYTE avgR = sumR / count; BYTE avgG = sumG / count; BYTE avgB = sumB / count; // 使用ProcessSinglePixel处理(基于马赛克平均颜色) BYTE mosaicPixel[3] = { avgB, avgG, avgR }; ProcessSinglePixel(pDestPixel, brightness, saturation, bBlackWhite, bSepia, mosaicPixel); } } else { // 无马赛克效果,直接使用原图像素 BYTE* pSrcPixel = &pSrc[y * srcPitch + x * channels]; ProcessSinglePixel(pDestPixel, brightness, saturation, bBlackWhite, bSepia, pSrcPixel); } } } } // 5. 刷新显示 RedrawSelectionArea(validRect); //if (!layer.displayImage.IsNull()) { // // 方法1:使用BitBlt复制(推荐) // layer.image.Destroy(); // 先销毁旧图像 // layer.image.Create(layer.displayImage.GetWidth(), // layer.displayImage.GetHeight(), // layer.displayImage.GetBPP()); // HDC hdcSrc = layer.displayImage.GetDC(); // HDC hdcDst = layer.image.GetDC(); // BitBlt(hdcDst, 0, 0, layer.displayImage.GetWidth(), layer.displayImage.GetHeight(), // hdcSrc, 0, 0, SRCCOPY); // layer.displayImage.ReleaseDC(); // layer.image.ReleaseDC(); //} } void CMyPS2Dlg::ProcessSinglePixel(BYTE* pPixel, int brightness, float saturation, bool bBlackWhite, bool bSepia, const BYTE* pOriginalPixel = nullptr) // 新增原始像素参数 { // 默认使用当前像素作为原始值(兼容旧代码) BYTE origB = pOriginalPixel ? pOriginalPixel[0] : pPixel[0]; BYTE origG = pOriginalPixel ? pOriginalPixel[1] : pPixel[1]; BYTE origR = pOriginalPixel ? pOriginalPixel[2] : pPixel[2]; // 亮度调整(基于原始值的非线性变换) // brightness=100 → 2.0倍 float r = min(255.0f, max(0.0f, (float)(origR + brightness))); float g = min(255.0f, max(0.0f, (float)(origG + brightness))); float b = min(255.0f, max(0.0f, (float)(origB + brightness))); // 饱度调整(保持基于原始值) if (saturation != 1.0f) { float gray = 0.299f * origR + 0.587f * origG + 0.114f * origB; r = min(255.0f,max(0.0f,(float)(gray + saturation * (r - gray)))); g = min(255.0f, max(0.0f, (float)(gray + saturation * (g - gray)))); b = min(255.0f, max(0.0f, (float)(gray + saturation * (b - gray)))); } // 写入目标像素(限幅) pPixel[0] = static_cast<BYTE>(min(255, max(0, static_cast<int>(b)))); pPixel[1] = static_cast<BYTE>(min(255, max(0, static_cast<int>(g)))); pPixel[2] = static_cast<BYTE>(min(255, max(0, static_cast<int>(r)))); // 滤镜处理(互斥) if (bBlackWhite || bSepia) { BYTE gray = static_cast<BYTE>(0.299f * pPixel[2] + 0.587f * pPixel[1] + 0.114f * pPixel[0]); if (bBlackWhite) { pPixel[0] = pPixel[1] = pPixel[2] = gray; } else if (bSepia) { pPixel[2] = min(255, static_cast<int>(0.393 * pPixel[2] + 0.769 * pPixel[1] + 0.189 * pPixel[0])); pPixel[1] = min(255, static_cast<int>(0.349 * pPixel[2] + 0.686 * pPixel[1] + 0.168 * pPixel[0])); pPixel[0] = min(255, static_cast<int>(0.272 * pPixel[2] + 0.534 * pPixel[1] + 0.131 * pPixel[0])); } } } void CMyPS2Dlg::RedrawSelectionArea(const CRect& imageRect) { // 1. 检查输入有效性 if (imageRect.IsRectEmpty() ||( m_layer1.displayImage.IsNull()&&m_layer2.displayImage.IsNull())) return; // 2. 精确坐标转换 CRect screenRect = ConvertToScreenRect(imageRect); // 3. 验证屏幕区域有效性 CRect clientRect; GetClientRect(&clientRect); if (!screenRect.IntersectRect(screenRect, clientRect)) return; // 4. 动态调整扩大范围 int inflate = max(2, min(10, screenRect.Width() / 20)); screenRect.InflateRect(inflate, inflate); // 5. 安全刷新 if (!screenRect.IsRectEmpty()) { RedrawWindow(screenRect, NULL, RDW_INVALIDATE | RDW_UPDATENOW | RDW_NOERASE | RDW_NOCHILDREN); } } // 将图像坐标系中的矩形转换为屏幕客户区坐标 CRect CMyPS2Dlg::ConvertToScreenRect(const CRect& imageRect) { if (m_layer1.isSelected) { if (m_layer1.displayImage.IsNull()) return CRect(0, 0, 0, 0); CRect imgClientRect = GetImageClientRect(m_layer1.image); return CRect( imgClientRect.left + imageRect.left * imgClientRect.Width() / m_layer1.displayImage.GetWidth(), imgClientRect.top + imageRect.top * imgClientRect.Height() / m_layer1.displayImage.GetHeight(), imgClientRect.left + imageRect.right * imgClientRect.Width() / m_layer1.displayImage.GetWidth(), imgClientRect.top + imageRect.bottom * imgClientRect.Height() / m_layer1.displayImage.GetHeight() ); } else { if (m_layer2.displayImage.IsNull()) return CRect(0, 0, 0, 0); CRect imgClientRect = GetImageClientRect(m_layer2.image); return CRect( imgClientRect.left + imageRect.left * imgClientRect.Width() / m_layer2.displayImage.GetWidth(), imgClientRect.top + imageRect.top * imgClientRect.Height() / m_layer2.displayImage.GetHeight(), imgClientRect.left + imageRect.right * imgClientRect.Width() / m_layer2.displayImage.GetWidth(), imgClientRect.top + imageRect.bottom * imgClientRect.Height() / m_layer2.displayImage.GetHeight() ); } } BOOL CMyPS2Dlg::OnEraseBkgnd(CDC* pDC) { return TRUE; // 完全禁用背景擦除 } // 获取位图实际尺寸的辅助函数 CSize CMyPS2Dlg::GetBitmapDimension(CBitmap& bitmap) { BITMAP bm; if (bitmap.GetSafeHandle() && bitmap.GetBitmap(&bm)) return CSize(bm.bmWidth, bm.bmHeight); return CSize(0, 0); } //规则选区 void CMyPS2Dlg::OnBnClickedButton9() { m_selectionMode = SELECT_RECTANGLE; ResetSelection(); // 重置选区状态 // TODO: 在此添加控件通知处理程序代码 } //不规则选区 void CMyPS2Dlg::OnBnClickedButton10() { m_selectionMode = SELECT_FREE_FORM; ResetSelection(); // 添加调试输出 TRACE(_T("不规则选区模式已激活\n")); // 强制重绘以确保状态更新 Invalidate(); // TODO: 在此添加控件通知处理程序代码 } //添加图层 void CMyPS2Dlg::OnBnClickedButton11() { if (!m_layer2.image.IsNull()) { UINT i; i = MessageBox(_T(“确认重新打开图片吗?”), _T(“提示”), MB_YESNO | MB_ICONQUESTION); if (i != IDYES) { return; } } CFileDialog dlg(TRUE, _T(“.bmp;.jpg;.png"), NULL, OFN_FILEMUSTEXIST, _T("Image Files|.bmp;.jpg;.png||”), this); if (dlg.DoModal() == IDOK) { // 释放旧资源 m_layer2.history.clear(); m_layer2.currentHistoryIndex = -1; m_layer1.isSelected = false; m_layer2.isSelected = true; if (!m_layer2.image.IsNull()) { m_layer2.image.Destroy(); } if (!m_layer2.displayImage.IsNull()) { m_layer2.displayImage.Destroy(); } if (m_layer2.image.Load(dlg.GetPathName()) != S_OK) { AfxMessageBox(L"图像加载失败!\n请检查格式支持(BMP/JPG/PNG)"); return; } else { // 加载新图像 ImageState initialState; initialState.brightness = 0; initialState.saturation = 1.0f; initialState.mosaic = 1; initialState.alpha = 0.5f; if (!m_layer2.image.IsNull()) { if (!initialState.image.IsNull()) { initialState.image.Destroy(); } initialState.image.Create(m_layer2.image.GetWidth(), m_layer2.image.GetHeight(), m_layer2.image.GetBPP()); CDC* pSrcDC = CDC::FromHandle(m_layer2.image.GetDC()); CDC* pDstDC = CDC::FromHandle(initialState.image.GetDC()); pDstDC->BitBlt(0, 0, m_layer2.image.GetWidth(), m_layer2.image.GetHeight(), pSrcDC, 0, 0, SRCCOPY); m_layer2.image.ReleaseDC(); initialState.image.ReleaseDC(); } m_layer2.history.push_back(initialState); m_layer2.history.push_back(initialState); m_layer2.currentHistoryIndex = 1; // 重置所有参数 m_nlightValue = 0; m_nsatureValue = 1.0f; m_nmskValue = 1; m_layer1.alpha = 1.0f; // 重置底层透明度为不透明 m_layer2.alpha = 0.5f; // 重置顶层透明度为半透明 // 初始化UI控件 litslider.SetPos(100); // 假设滑块范围0-200,100对应亮度0 saturslider.SetPos(100); // 假设滑块范围0-200,100对应饱度1.0 mskslider.SetPos(1); // 马赛克块大小(1~20) m_sliderLay1.SetPos(100); // 新增:底层透明度滑块(0-100) m_sliderLay2.SetPos(50); // 新增:顶层透明度滑块(0-100) // 生成显示图像 UpdateDisplayImage(m_layer2); } } // TODO: 在此添加控件通知处理程序代码 } void CMyPS2Dlg::OnNMCustomdrawSliderl1(NMHDR* pNMHDR, LRESULT* pResult) { LPNMCUSTOMDRAW pNMCD = reinterpret_cast(pNMHDR); // TODO: 在此添加控件通知处理程序代码 *pResult = 0; } void CMyPS2Dlg::ResetSelection() { m_bSelecting = false; m_bFreeFormSelecting = false; m_rcSelection.SetRectEmpty(); // 清理不规则选区资源 if (m_rgnFreeForm.GetSafeHandle()) { m_rgnFreeForm.DeleteObject(); } m_freeFormPoints.clear(); Invalidate(); } BOOL CMyPS2Dlg::HasSelection() const { if (m_selectionMode == SELECT_RECTANGLE) { return !m_rcSelection.IsRectNull(); } else { return m_rgnFreeForm.GetSafeHandle() != NULL; } } void CMyPS2Dlg::CleanUpResources() { // 清理双缓冲资源 if (m_memDC.GetSafeHdc()) { m_memDC.SelectObject((HBITMAP)NULL); m_memDC.DeleteDC(); } if (m_memBitmap.GetSafeHandle()) { m_memBitmap.DeleteObject(); } // 清理其他GDI资源 if (m_rgnFreeForm.GetSafeHandle()) { m_rgnFreeForm.DeleteObject(); } } CPoint CMyPS2Dlg::ConvertToScreenPoint(CPoint imagePoint) { if (m_layer1.isSelected) { CRect imgRect = GetImageClientRect(m_layer1.image); return CPoint( imgRect.left + imagePoint.x * imgRect.Width() / m_layer1.displayImage.GetWidth(), imgRect.top + imagePoint.y * imgRect.Height() / m_layer1.displayImage.GetHeight() ); } else { CRect imgRect = GetImageClientRect(m_layer2.image); return CPoint( imgRect.left + imagePoint.x * imgRect.Width() / m_layer2.displayImage.GetWidth(), imgRect.top + imagePoint.y * imgRect.Height() / m_layer2.displayImage.GetHeight() ); } } void CMyPS2Dlg::SelectLayer(bool selectLayer1) { m_layer1.isSelected = selectLayer1; m_layer2.isSelected = !selectLayer1; // 更新滑块显示当前图层的透明度 if (selectLayer1) { m_sliderLay1.SetPos(static_cast<int>(m_layer1.alpha * 100.0f)); } else { m_sliderLay2.SetPos(static_cast<int>(m_layer2.alpha * 100.0f)); } Invalidate(); // 刷新显示 } //选择图层 void CMyPS2Dlg::OnBnClickedButton12() { SelectLayer(!m_layer1.isSelected); if (m_layer1.isSelected) { if (m_layer1.displayImage.IsNull()) { AfxMessageBox(_T(“请先打开图片”)); } else { AfxMessageBox(_T(“已选 图层1”)); } } else { if (m_layer2.displayImage.IsNull()) { AfxMessageBox(_T(“请先打开图片”)); } else { AfxMessageBox(_T(“已选 图层2”)); } } // TODO: 在此添加控件通知处理程序代码 } //开始涂鸦 void CMyPS2Dlg::OnBnClickedButton13() { StartDoodleMode(); // TODO: 在此添加控件通知处理程序代码 } //应用涂鸦 void CMyPS2Dlg::OnBnClickedButton14() { EndDoodleMode(true); // TODO: 在此添加控件通知处理程序代码 } //取消涂鸦 void CMyPS2Dlg::OnBnClickedButton15() { EndDoodleMode(false); // TODO: 在此添加控件通知处理程序代码 } //颜色滑块 void CMyPS2Dlg::OnNMCustomdrawSlidercol(NMHDR* pNMHDR, LRESULT* pResult) { LPNMCUSTOMDRAW pNMCD = reinterpret_cast(pNMHDR); CSliderCtrl* pSlider = (CSliderCtrl*)GetDlgItem(IDC_SLIDERCOL); if (pSlider) { int pos = pSlider->GetPos(); // 将滑块位置转换为颜色 (0-360度色相) m_doodleColor = HSLtoRGB(pos, 1.0, 0.5); } *pResult = 0; } // HSL转RGB辅助函数 COLORREF CMyPS2Dlg::HSLtoRGB(float H, float S, float L) { float C = (1 - fabs(2 * L - 1)) * S; float X = C * (1 - fabs(fmod(H / 60.0, 2) - 1)); float m = L - C / 2; float R, G, B; if (H >= 0 && H < 60) { R = C; G = X; B = 0; } else if (H >= 60 && H < 120) { R = X; G = C; B = 0; } else if (H >= 120 && H < 180) { R = 0; G = C; B = X; } else if (H >= 180 && H < 240) { R = 0; G = X; B = C; } else if (H >= 240 && H < 300) { R = X; G = 0; B = C; } else { R = C; G = 0; B = X; } BYTE r = (BYTE)((R + m) * 255); BYTE g = (BYTE)((G + m) * 255); BYTE b = (BYTE)((B + m) * 255); return RGB(r, g, b); } //粗细滑块 void CMyPS2Dlg::OnNMCustomdrawSliderthi(NMHDR* pNMHDR, LRESULT* pResult) { LPNMCUSTOMDRAW pNMCD = reinterpret_cast(pNMHDR); CSliderCtrl* pSlider = (CSliderCtrl*)GetDlgItem(IDC_SLIDERTHI); if (pSlider) { m_doodleThickness = pSlider->GetPos(); } *pResult = 0; } void CMyPS2Dlg::StartDoodleMode() { ImageLayer& activeLayer = m_layer1.isSelected ? m_layer1 : m_layer2; if (activeLayer.displayImage.IsNull()) { AfxMessageBox(_T(“请先打开图片”)); return; } // 创建临时位图 if (!m_doodleTempImage.IsNull()) m_doodleTempImage.Destroy(); int width = activeLayer.displayImage.GetWidth(); int height = activeLayer.displayImage.GetHeight(); m_doodleTempImage.Create(width, height, activeLayer.displayImage.GetBPP()); // 复制当前显示图像到临时位图 CDC* pSrcDC = CDC::FromHandle(activeLayer.displayImage.GetDC()); CDC* pDstDC = CDC::FromHandle(m_doodleTempImage.GetDC()); pDstDC->BitBlt(0, 0, width, height, pSrcDC, 0, 0, SRCCOPY); activeLayer.displayImage.ReleaseDC(); m_doodleTempImage.ReleaseDC(); // 重置涂鸦数据 m_doodleLines.clear(); m_bDoodleMode = true; m_bDoodling = false; // 设置鼠标光标 SetCursor(LoadCursor(NULL, IDC_CROSS)); } // 结束涂鸦模式 void CMyPS2Dlg::EndDoodleMode(bool apply) { if (!m_bDoodleMode) return; if (apply) { ApplyDoodleToImage(); } // 清理资源 m_doodleTempImage.Destroy(); m_doodleLines.clear(); m_bDoodleMode = false; m_bDoodling = false; // 恢复鼠标光标 SetCursor(LoadCursor(NULL, IDC_ARROW)); // 刷新显示 Invalidate(FALSE); } // 将涂鸦应用到当前图层(有改) void CMyPS2Dlg::ApplyDoodleToImage() { ImageLayer* activeLayer = m_layer1.isSelected ? &m_layer1 : &m_layer2; if (activeLayer->image.IsNull()) return; // 获取设备上下文 CDC* pDC = CDC::FromHandle(activeLayer->image.GetDC()); CPen pen(PS_SOLID, m_doodleThickness, m_doodleColor); CPen* pOldPen = pDC->SelectObject(&pen); // 绘制所有涂鸦线段 for (const auto& line : m_doodleLines) { pDC->MoveTo(line.first); pDC->LineTo(line.second); } pDC->SelectObject(pOldPen); activeLayer->image.ReleaseDC(); doodend = true; m_bStateDirty = true; // 更新显示图像并保存状态 UpdateDisplayImage(*activeLayer); SaveCurrentState(*activeLayer); } // 绘制一条涂鸦线段 void CMyPS2Dlg::DrawDoodleLine(CPoint start, CPoint end) { if (m_doodleTempImage.IsNull()) return; CDC* pDC = CDC::FromHandle(m_doodleTempImage.GetDC()); CPen pen(PS_SOLID, m_doodleThickness, m_doodleColor); CPen* pOldPen = pDC->SelectObject(&pen); pDC->MoveTo(start); pDC->LineTo(end); pDC->SelectObject(pOldPen); m_doodleTempImage.ReleaseDC(); // 将线段添加到列表 m_doodleLines.push_back(std::make_pair(start, end)); } //复制选区 void CMyPS2Dlg::OnBnClickedButton16() { ImageLayer& activelayer = m_layer1.isSelected ? m_layer1 : m_layer2; if (!HasSelection()) { AfxMessageBox(_T(“请先创建选区”)); return; } if (!activelayer.clonedRegion.active) { // 首次复制:创建克隆区域 CRect selRect = GetSelectionRect(); activelayer.clonedRegion.sourceRect = selRect; activelayer.clonedRegion.destRect = selRect; activelayer.clonedRegion.active = true; activelayer.clonedRegion.visible = true; // 复制图像数据 - 从displayImage复制而不是image activelayer.clonedRegion.image.Destroy(); activelayer.clonedRegion.image.Create(selRect.Width(), selRect.Height(), activelayer.displayImage.GetBPP()); // 使用displayImage作为源 CDC* pSrcDC = CDC::FromHandle(activelayer.displayImage.GetDC()); CDC* pDstDC = CDC::FromHandle(activelayer.clonedRegion.image.GetDC()); pDstDC->BitBlt(0, 0, selRect.Width(), selRect.Height(), pSrcDC, selRect.left, selRect.top, SRCCOPY); activelayer.displayImage.ReleaseDC(); activelayer.clonedRegion.image.ReleaseDC(); TRACE(_T("创建克隆区域(带效果)\n")); TRACE(_T("选区位置: (%d, %d) - (%d, %d)\n"), selRect.left, selRect.top, selRect.right, selRect.bottom); } else { // 切换显示状态 activelayer.clonedRegion.visible = !activelayer.clonedRegion.visible; // 添加调试输出 TRACE(_T("切换克隆区域可见性: %s\n"), activelayer.clonedRegion.visible ? _T("可见") : _T("隐藏")); } Invalidate(); // 刷新显示 // 添加状态栏提示 /*CString msg; msg.Format(_T("克隆区域已%s"), activelayer.clonedRegion.visible ? _T("显示") : _T("隐藏")); GetDlgItem(IDC_STATIC)->SetWindowText(msg);*/ // 切换显示状态 //activeLayer.clonedRegion.visible = !activeLayer.clonedRegion.visible; //Invalidate(); // TODO: 在此添加控件通知处理程序代码 } CRect CMyPS2Dlg::GetSelectionRect() { if (m_selectionMode == SELECT_RECTANGLE && !m_rcSelection.IsRectNull()) { return m_rcSelection; } else if (m_selectionMode == SELECT_FREE_FORM && m_rgnFreeForm.GetSafeHandle()) { CRect rect; m_rgnFreeForm.GetRgnBox(&rect); return rect; } return CRect(0, 0, 0, 0); // 无选区 }为什么这段函数能实现在同一图层,出现多个统一类型的选区,且相互独立
07-03
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值