diff --git a/Ink Canvas/Windows/PPTQuickPanel.xaml b/Ink Canvas/Windows/PPTQuickPanel.xaml index 3056766d..6a7262ea 100644 --- a/Ink Canvas/Windows/PPTQuickPanel.xaml +++ b/Ink Canvas/Windows/PPTQuickPanel.xaml @@ -170,27 +170,52 @@ - - + + + + + + + + @@ -216,3 +241,4 @@ + diff --git a/Ink Canvas/Windows/PPTQuickPanel.xaml.cs b/Ink Canvas/Windows/PPTQuickPanel.xaml.cs index d4d5eedd..281e421a 100644 --- a/Ink Canvas/Windows/PPTQuickPanel.xaml.cs +++ b/Ink Canvas/Windows/PPTQuickPanel.xaml.cs @@ -1,6 +1,7 @@ using Ink_Canvas.Helpers; using System; using System.Collections.Generic; +using System.Collections.Specialized; using System.IO; using System.Linq; using System.Runtime.InteropServices; @@ -9,6 +10,7 @@ using System.Windows.Controls; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Animation; +using System.Windows.Media.Imaging; using System.Windows.Threading; using Microsoft.Win32; using Newtonsoft.Json; @@ -134,16 +136,128 @@ namespace Ink_Canvas.Windows // 获取MainWindow引用 _mainWindow = Application.Current.MainWindow as MainWindow; - // 订阅PPT事件 SubscribeToPPTEvents(); - - // 延迟初始化音量显示,确保音频设备已初始化 + SubscribeToInkCanvasChildrenChanges(); Dispatcher.BeginInvoke(new Action(() => { UpdateVolumeDisplay(); }), DispatcherPriority.Loaded); } + private void SubscribeToInkCanvasChildrenChanges() + { + try + { + if (_mainWindow == null) return; + + System.Windows.Controls.InkCanvas inkCanvas = null; + var inkCanvasField = _mainWindow.GetType().GetField("inkCanvas", + System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public); + if (inkCanvasField != null) + { + inkCanvas = inkCanvasField.GetValue(_mainWindow) as System.Windows.Controls.InkCanvas; + } + if (inkCanvas == null) + { + var inkCanvasProperty = _mainWindow.GetType().GetProperty("inkCanvas", + System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public); + inkCanvas = inkCanvasProperty?.GetValue(_mainWindow) as System.Windows.Controls.InkCanvas; + } + + if (inkCanvas != null && inkCanvas.Children is INotifyCollectionChanged notifyCollection) + { + notifyCollection.CollectionChanged += InkCanvasChildren_CollectionChanged; + } + } + catch (Exception ex) + { + LogHelper.WriteLogToFile($"订阅inkCanvas.Children变化事件失败: {ex.Message}", LogHelper.LogType.Error); + } + } + + private void InkCanvasChildren_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) + { + try + { + if (e.Action == NotifyCollectionChangedAction.Remove) + { + foreach (var item in e.OldItems) + { + if (item is System.Windows.Controls.Image image) + { + RemoveImageFromPPT(image); + } + } + } + } + catch (Exception ex) + { + LogHelper.WriteLogToFile($"处理inkCanvas.Children变化失败: {ex.Message}", LogHelper.LogType.Error); + } + } + + private void RemoveImageFromPPT(System.Windows.Controls.Image image) + { + try + { + if (image == null) return; + + if (_pptImages.ContainsKey(image)) + { + int slideNumber = _pptImages[image]; + _pptImages.Remove(image); + + if (_pptImagePaths.ContainsKey(slideNumber)) + { + string imagePath = image.Tag as string; + if (!string.IsNullOrEmpty(imagePath) && _pptImagePaths[slideNumber].Contains(imagePath)) + { + _pptImagePaths[slideNumber].Remove(imagePath); + + if (_pptImagePaths[slideNumber].Count == 0) + { + _pptImagePaths.Remove(slideNumber); + DeletePPTImagePathsFile(slideNumber); + } + else + { + SavePPTImagePaths(slideNumber); + } + + LogHelper.WriteLogToFile($"已从PPT页面{slideNumber}移除图片: {imagePath}"); + } + } + } + } + catch (Exception ex) + { + LogHelper.WriteLogToFile($"从PPT关联数据中移除图片失败: {ex.Message}", LogHelper.LogType.Error); + } + } + + private void DeletePPTImagePathsFile(int slideIndex) + { + try + { + if (slideIndex <= 0) return; + + var folderPath = GetPresentationFolderPath(); + if (string.IsNullOrEmpty(folderPath) || !Directory.Exists(folderPath)) + return; + + var jsonFilePath = Path.Combine(folderPath, slideIndex.ToString("0000") + ".images.json"); + if (File.Exists(jsonFilePath)) + { + File.Delete(jsonFilePath); + LogHelper.WriteLogToFile($"已删除第{slideIndex}页图片路径JSON文件: {jsonFilePath}"); + } + } + catch (Exception ex) + { + LogHelper.WriteLogToFile($"删除PPT图片路径JSON文件失败: {ex.Message}", LogHelper.LogType.Error); + } + } + private void SubscribeToPPTEvents() { try @@ -359,6 +473,38 @@ namespace Ink_Canvas.Windows private void PPTQuickPanel_Unloaded(object sender, RoutedEventArgs e) { SystemEvents.UserPreferenceChanged -= SystemEvents_UserPreferenceChanged; + UnsubscribeFromInkCanvasChildrenChanges(); + } + + private void UnsubscribeFromInkCanvasChildrenChanges() + { + try + { + if (_mainWindow == null) return; + + System.Windows.Controls.InkCanvas inkCanvas = null; + var inkCanvasField = _mainWindow.GetType().GetField("inkCanvas", + System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public); + if (inkCanvasField != null) + { + inkCanvas = inkCanvasField.GetValue(_mainWindow) as System.Windows.Controls.InkCanvas; + } + if (inkCanvas == null) + { + var inkCanvasProperty = _mainWindow.GetType().GetProperty("inkCanvas", + System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public); + inkCanvas = inkCanvasProperty?.GetValue(_mainWindow) as System.Windows.Controls.InkCanvas; + } + + if (inkCanvas != null && inkCanvas.Children is INotifyCollectionChanged notifyCollection) + { + notifyCollection.CollectionChanged -= InkCanvasChildren_CollectionChanged; + } + } + catch (Exception ex) + { + LogHelper.WriteLogToFile($"取消订阅inkCanvas.Children变化事件失败: {ex.Message}", LogHelper.LogType.Error); + } } private void SystemEvents_UserPreferenceChanged(object sender, UserPreferenceChangedEventArgs e) @@ -775,13 +921,12 @@ namespace Ink_Canvas.Windows #region 图片插入 - private async void InsertImageButton_Click(object sender, RoutedEventArgs e) + private async void InsertImageSelectFileButton_Click(object sender, RoutedEventArgs e) { if (_mainWindow == null) return; try { - // 调用MainWindow的图片插入功能 var dialog = new OpenFileDialog { Filter = "图片文件|*.jpg;*.jpeg;*.png;*.bmp;*.gif" @@ -791,7 +936,6 @@ namespace Ink_Canvas.Windows { string filePath = dialog.FileName; - // 使用反射调用MainWindow的CreateAndCompressImageAsync方法 var createImageMethod = _mainWindow.GetType().GetMethod("CreateAndCompressImageAsync", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); @@ -804,8 +948,6 @@ namespace Ink_Canvas.Windows if (image != null) { image.Tag = filePath; - - // 使用反射调用MainWindow的图片插入相关方法 await InsertImageToMainWindow(image, filePath); } } @@ -822,6 +964,227 @@ namespace Ink_Canvas.Windows } } + private async void InsertImageScreenshotButton_Click(object sender, RoutedEventArgs e) + { + if (_mainWindow == null) return; + + try + { + var captureScreenshotMethod = _mainWindow.GetType().GetMethod("CaptureScreenshotAndInsert", + System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); + + if (captureScreenshotMethod != null) + { + var task = captureScreenshotMethod.Invoke(_mainWindow, null) as System.Threading.Tasks.Task; + if (task != null) + { + await task; + await SaveScreenshotToPPT(); + } + } + else + { + LogHelper.WriteLogToFile("无法找到CaptureScreenshotAndInsert方法", LogHelper.LogType.Warning); + } + } + catch (Exception ex) + { + LogHelper.WriteLogToFile($"截图插入失败: {ex.Message}", LogHelper.LogType.Error); + } + } + + private async System.Threading.Tasks.Task SaveScreenshotToPPT() + { + try + { + if (_mainWindow == null) return; + + System.Windows.Controls.InkCanvas inkCanvas = null; + var inkCanvasField = _mainWindow.GetType().GetField("inkCanvas", + System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public); + if (inkCanvasField != null) + { + inkCanvas = inkCanvasField.GetValue(_mainWindow) as System.Windows.Controls.InkCanvas; + } + if (inkCanvas == null) + { + var inkCanvasProperty = _mainWindow.GetType().GetProperty("inkCanvas", + System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public); + inkCanvas = inkCanvasProperty?.GetValue(_mainWindow) as System.Windows.Controls.InkCanvas; + } + + if (inkCanvas == null) return; + + System.Windows.Controls.Image lastScreenshot = null; + foreach (System.Windows.Controls.Image img in inkCanvas.Children.OfType()) + { + if (img.Name != null && (img.Name.StartsWith("screenshot_") || img.Name.StartsWith("camera_")) && img.Tag == null) + { + lastScreenshot = img; + } + } + + if (lastScreenshot == null) return; + + string screenshotFilePath = await SaveScreenshotToFile(lastScreenshot); + + if (string.IsNullOrEmpty(screenshotFilePath)) + { + LogHelper.WriteLogToFile("保存截图文件失败", LogHelper.LogType.Warning); + return; + } + + lastScreenshot.Tag = screenshotFilePath; + await ManageScreenshotInPPT(lastScreenshot, screenshotFilePath); + } + catch (Exception ex) + { + LogHelper.WriteLogToFile($"保存截图到PPT失败: {ex.Message}", LogHelper.LogType.Error); + } + } + + private async System.Threading.Tasks.Task SaveScreenshotToFile(System.Windows.Controls.Image image) + { + try + { + if (image?.Source == null) return null; + + string savePath = null; + var settingsProperty = _mainWindow.GetType().GetProperty("Settings"); + if (settingsProperty != null) + { + var settings = settingsProperty.GetValue(_mainWindow); + if (settings != null) + { + var autoSavedStrokesLocationProperty = settings.GetType().GetProperty("Automation"); + if (autoSavedStrokesLocationProperty != null) + { + var automation = autoSavedStrokesLocationProperty.GetValue(settings); + if (automation != null) + { + var locationProperty = automation.GetType().GetProperty("AutoSavedStrokesLocation"); + if (locationProperty != null) + { + var location = locationProperty.GetValue(automation) as string; + if (!string.IsNullOrEmpty(location)) + { + savePath = Path.Combine(location, "File Dependency"); + } + } + } + } + } + } + + if (string.IsNullOrEmpty(savePath)) + { + LogHelper.WriteLogToFile("无法获取AutoSavedStrokesLocation", LogHelper.LogType.Warning); + return null; + } + + if (!Directory.Exists(savePath)) + { + Directory.CreateDirectory(savePath); + } + + string timestamp = image.Name; + string filePath = Path.Combine(savePath, timestamp + ".png"); + + await Application.Current.Dispatcher.InvokeAsync(() => + { + if (image.Source is BitmapSource bitmapSource) + { + var encoder = new PngBitmapEncoder(); + encoder.Frames.Add(BitmapFrame.Create(bitmapSource)); + + using (var fileStream = new FileStream(filePath, FileMode.Create)) + { + encoder.Save(fileStream); + } + } + }); + + return filePath; + } + catch (Exception ex) + { + LogHelper.WriteLogToFile($"保存截图到文件失败: {ex.Message}", LogHelper.LogType.Error); + return null; + } + } + + private async System.Threading.Tasks.Task ManageScreenshotInPPT(System.Windows.Controls.Image image, string filePath) + { + if (_mainWindow == null || image == null || string.IsNullOrEmpty(filePath)) return; + + await Application.Current.Dispatcher.InvokeAsync(() => + { + try + { + int currentSlideNumber = 0; + try + { + var pptManagerProperty = _mainWindow.GetType().GetProperty("PPTManager", + System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public); + var pptManager = pptManagerProperty?.GetValue(_mainWindow); + + if (pptManager != null) + { + var isInSlideShowProperty = pptManager.GetType().GetProperty("IsInSlideShow"); + bool isInSlideShow = false; + if (isInSlideShowProperty != null) + { + var result = isInSlideShowProperty.GetValue(pptManager); + if (result != null) + { + isInSlideShow = (bool)result; + } + } + + if (isInSlideShow) + { + var getCurrentSlideNumberMethod = pptManager.GetType().GetMethod("GetCurrentSlideNumber"); + if (getCurrentSlideNumberMethod != null) + { + var result = getCurrentSlideNumberMethod.Invoke(pptManager, null); + if (result != null) + { + currentSlideNumber = (int)result; + } + } + } + } + } + catch (Exception ex) + { + LogHelper.WriteLogToFile($"获取当前PPT页面编号失败: {ex.Message}", LogHelper.LogType.Warning); + } + + if (currentSlideNumber > 0 && !string.IsNullOrEmpty(filePath)) + { + _pptImages[image] = currentSlideNumber; + + if (!_pptImagePaths.ContainsKey(currentSlideNumber)) + { + _pptImagePaths[currentSlideNumber] = new List(); + } + _pptImagePaths[currentSlideNumber].Add(filePath); + SavePPTImagePaths(currentSlideNumber); + + LogHelper.WriteLogToFile($"截图已关联到PPT页面{currentSlideNumber}: {filePath}"); + } + else if (currentSlideNumber > 0) + { + _pptImages[image] = currentSlideNumber; + } + } + catch (Exception ex) + { + LogHelper.WriteLogToFile($"管理截图在PPT中的关联失败: {ex.Message}", LogHelper.LogType.Error); + } + }, DispatcherPriority.Normal); + } + private async System.Threading.Tasks.Task InsertImageToMainWindow(System.Windows.Controls.Image image, string originalFilePath = null, bool saveToJson = true) { if (_mainWindow == null || image == null) return; @@ -839,10 +1202,7 @@ namespace Ink_Canvas.Windows image.IsHitTestVisible = true; image.Focusable = false; - // 获取inkCanvas - 尝试字段和属性两种方式 System.Windows.Controls.InkCanvas inkCanvas = null; - - // 先尝试字段 var inkCanvasField = _mainWindow.GetType().GetField("inkCanvas", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public); if (inkCanvasField != null) @@ -850,7 +1210,6 @@ namespace Ink_Canvas.Windows inkCanvas = inkCanvasField.GetValue(_mainWindow) as System.Windows.Controls.InkCanvas; } - // 如果字段获取失败,尝试属性 if (inkCanvas == null) { var inkCanvasProperty = _mainWindow.GetType().GetProperty("inkCanvas",