diff --git a/Ink Canvas/Controls/PdfEmbeddedView.cs b/Ink Canvas/Controls/PdfEmbeddedView.cs index e5ea8bc4..c6bbb9f2 100644 --- a/Ink Canvas/Controls/PdfEmbeddedView.cs +++ b/Ink Canvas/Controls/PdfEmbeddedView.cs @@ -20,7 +20,6 @@ namespace Ink_Canvas.Controls private uint _currentIndex; private bool _compressLargePictures; private bool _isPagingBusy; - private bool _layoutSizeLocked; /// 页码或可翻页状态变化(用于更新侧栏)。 public event EventHandler PageNavigationStateChanged; @@ -42,14 +41,18 @@ namespace Ink_Canvas.Controls } /// - /// 初始化并显示第一页;由 MainWindow 在 UI 线程创建后调用。 + /// 初始化并显示指定页;由 MainWindow 在 UI 线程创建后调用。 /// - public async Task InitializeAsync(string pdfFilePath, uint pageCount, bool compressLargePictures) + /// 从 0 开始的页码,超出范围时夹紧到合法区间。 + public async Task InitializeAsync(string pdfFilePath, uint pageCount, bool compressLargePictures, uint initialPageIndex = 0) { _pdfPath = pdfFilePath ?? throw new ArgumentNullException(nameof(pdfFilePath)); _pageCount = pageCount; _compressLargePictures = compressLargePictures; - _currentIndex = 0; + if (_pageCount == 0) + _currentIndex = 0; + else + _currentIndex = initialPageIndex >= _pageCount ? _pageCount - 1 : initialPageIndex; await ShowPageAsync(_currentIndex); } @@ -104,12 +107,9 @@ namespace Ink_Canvas.Controls BitmapSource display = ApplyCompressionIfNeeded(raw); _pageImage.Source = display; - if (!_layoutSizeLocked) - { - Width = display.PixelWidth; - Height = display.PixelHeight; - _layoutSizeLocked = true; - } + // 每页尺寸可能不同,与图片一致按当前页位图更新布局,避免翻页后内容被裁切或“消失” + Width = display.PixelWidth; + Height = display.PixelHeight; } finally { diff --git a/Ink Canvas/Helpers/PdfWinRtHelper.cs b/Ink Canvas/Helpers/PdfWinRtHelper.cs index 578b6931..58a17617 100644 --- a/Ink Canvas/Helpers/PdfWinRtHelper.cs +++ b/Ink Canvas/Helpers/PdfWinRtHelper.cs @@ -1,6 +1,5 @@ using System; using System.IO; -using System.Runtime.InteropServices.WindowsRuntime; using System.Threading.Tasks; using System.Windows; using System.Windows.Media.Imaging; diff --git a/Ink Canvas/MainWindow_cs/MW_BoardControls.cs b/Ink Canvas/MainWindow_cs/MW_BoardControls.cs index c8ea6c80..447cb267 100644 --- a/Ink Canvas/MainWindow_cs/MW_BoardControls.cs +++ b/Ink Canvas/MainWindow_cs/MW_BoardControls.cs @@ -1,3 +1,4 @@ +using Ink_Canvas.Controls; using Ink_Canvas.Helpers; using System; using System.Collections.Generic; @@ -81,7 +82,7 @@ namespace Ink_Canvas var missingElements = 0; foreach (UIElement child in inkCanvas.Children) { - if (child is Image || child is MediaElement) + if (child is Image || child is MediaElement || child is PdfEmbeddedView) { if (child is Image img && img.Tag is string tag && tag == VideoPresenterLiveFrameTag) { @@ -310,6 +311,16 @@ namespace Ink_Canvas } BindElementEvents(media); } + else if (element is PdfEmbeddedView pdf) + { + double left = InkCanvas.GetLeft(pdf); + double top = InkCanvas.GetTop(pdf); + if (double.IsNaN(left) || double.IsNaN(top)) + { + CenterAndScaleElement(pdf); + } + BindElementEvents(pdf); + } } })); } diff --git a/Ink Canvas/MainWindow_cs/MW_ElementsControls.cs b/Ink Canvas/MainWindow_cs/MW_ElementsControls.cs index 169d9f9e..b98881a5 100644 --- a/Ink Canvas/MainWindow_cs/MW_ElementsControls.cs +++ b/Ink Canvas/MainWindow_cs/MW_ElementsControls.cs @@ -1021,6 +1021,46 @@ namespace Ink_Canvas } } + /// 从保存的 恢复 PDF(与打开墨迹时的图片恢复流程一致,不单独写入时间轴)。 + private async Task RestorePdfFromElementInfoAsync(CanvasElementInfo info) + { + if (info == null || inkCanvas == null) return; + if (!string.Equals(info.Type, "Pdf", StringComparison.OrdinalIgnoreCase)) return; + if (string.IsNullOrEmpty(info.SourcePath) || !File.Exists(info.SourcePath)) return; + + try + { + uint pageCount = await PdfWinRtHelper.GetPageCountAsync(info.SourcePath); + if (pageCount == 0) return; + + bool compress = isLoaded && Settings.Canvas.IsCompressPicturesUploaded; + uint initial = 0; + if (info.PdfCurrentPage.HasValue) + initial = (uint)Math.Max(0, Math.Min(info.PdfCurrentPage.Value, (int)pageCount - 1)); + + var view = new PdfEmbeddedView + { + Name = "pdf_" + DateTime.Now.ToString("yyyyMMdd_HH_mm_ss_fff") + }; + await view.InitializeAsync(info.SourcePath, pageCount, compress, initial); + + if (info.Width > 0) view.Width = info.Width; + if (info.Height > 0) view.Height = info.Height; + + InkCanvas.SetLeft(view, info.Left); + InkCanvas.SetTop(view, info.Top); + + InitializeElementTransform(view); + BindElementEvents(view); + inkCanvas.Children.Add(view); + SyncPdfPageSidebarWithCanvas(); + } + catch (Exception ex) + { + LogHelper.WriteLogToFile($"从 .elements.json 恢复 PDF 失败: {ex.Message}", LogHelper.LogType.Error); + } + } + #endregion #region Media diff --git a/Ink Canvas/MainWindow_cs/MW_FloatingBarIcons.cs b/Ink Canvas/MainWindow_cs/MW_FloatingBarIcons.cs index 64ebf6ce..5a245e03 100644 --- a/Ink Canvas/MainWindow_cs/MW_FloatingBarIcons.cs +++ b/Ink Canvas/MainWindow_cs/MW_FloatingBarIcons.cs @@ -1,4 +1,3 @@ -using Ink_Canvas.Controls; using Ink_Canvas.Helpers; using iNKORE.UI.WPF.Modern; using System; @@ -19,7 +18,6 @@ using Application = System.Windows.Application; using Button = System.Windows.Controls.Button; using Cursors = System.Windows.Input.Cursors; using HorizontalAlignment = System.Windows.HorizontalAlignment; -using Image = System.Windows.Controls.Image; using MessageBox = iNKORE.UI.WPF.Modern.Controls.MessageBox; using MouseEventArgs = System.Windows.Input.MouseEventArgs; using OpenFileDialog = Microsoft.Win32.OpenFileDialog; diff --git a/Ink Canvas/MainWindow_cs/MW_Save&OpenStrokes.cs b/Ink Canvas/MainWindow_cs/MW_Save&OpenStrokes.cs index e55d8e15..bb42d7c5 100644 --- a/Ink Canvas/MainWindow_cs/MW_Save&OpenStrokes.cs +++ b/Ink Canvas/MainWindow_cs/MW_Save&OpenStrokes.cs @@ -1,3 +1,4 @@ +using Ink_Canvas.Controls; using Ink_Canvas.Helpers; using Newtonsoft.Json; using System; @@ -16,6 +17,7 @@ using System.Windows.Ink; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; +using System.Windows.Threading; using System.Xml; using System.Xml.Linq; using Color = System.Drawing.Color; @@ -28,16 +30,58 @@ namespace Ink_Canvas // 1. 定义元素信息结构 public class CanvasElementInfo { - public string Type { get; set; } // "Image" + public string Type { get; set; } // "Image" | "Pdf" public string SourcePath { get; set; } public double Left { get; set; } public double Top { get; set; } public double Width { get; set; } public double Height { get; set; } public string Stretch { get; set; } = "Fill"; // 默认为Fill + /// PDF 当前页(从 0 开始),仅 Type == Pdf 时有效。 + public int? PdfCurrentPage { get; set; } + /// 保存时的 PDF 总页数,用于校验;仅 Type == Pdf 时有效。 + public int? PdfPageCount { get; set; } } public partial class MainWindow : Window { + /// 收集画布上图片与 PDF 的元数据,写入 .elements.json(与墨迹文件同路径)。 + private void CollectCanvasElementsMetadata(List elementInfos) + { + if (elementInfos == null || inkCanvas == null) return; + + foreach (var child in inkCanvas.Children) + { + if (child is Image img && img.Source is BitmapImage bmp) + { + elementInfos.Add(new CanvasElementInfo + { + Type = "Image", + SourcePath = bmp.UriSource?.LocalPath ?? "", + Left = InkCanvas.GetLeft(img), + Top = InkCanvas.GetTop(img), + Width = img.Width, + Height = img.Height, + Stretch = img.Stretch.ToString() + }); + } + else if (child is PdfEmbeddedView pdf && !string.IsNullOrEmpty(pdf.PdfPath)) + { + elementInfos.Add(new CanvasElementInfo + { + Type = "Pdf", + SourcePath = pdf.PdfPath, + Left = InkCanvas.GetLeft(pdf), + Top = InkCanvas.GetTop(pdf), + Width = pdf.Width, + Height = pdf.Height, + Stretch = "Uniform", + PdfCurrentPage = (int)pdf.CurrentPageIndex, + PdfPageCount = (int)pdf.PageCount + }); + } + } + } + /// /// 保存墨迹的鼠标释放事件处理 /// @@ -419,22 +463,7 @@ namespace Ink_Canvas // 保存元素信息 var elementInfos = new List(); - foreach (var child in inkCanvas.Children) - { - if (child is Image img && img.Source is BitmapImage bmp) - { - elementInfos.Add(new CanvasElementInfo - { - Type = "Image", - SourcePath = bmp.UriSource?.LocalPath ?? "", - Left = InkCanvas.GetLeft(img), - Top = InkCanvas.GetTop(img), - Width = img.Width, - Height = img.Height, - Stretch = img.Stretch.ToString() - }); - } - } + CollectCanvasElementsMetadata(elementInfos); string elementsPath = Settings.Automation.IsSaveStrokesAsXML ? Path.ChangeExtension(savePathWithName, ".elements.json") : Path.ChangeExtension(savePathWithName, ".elements.json"); File.WriteAllText(elementsPath, JsonConvert.SerializeObject(elementInfos, Newtonsoft.Json.Formatting.Indented)); } @@ -485,22 +514,7 @@ namespace Ink_Canvas // 同时保存元素信息 var elementInfos = new List(); - foreach (var child in inkCanvas.Children) - { - if (child is Image img && img.Source is BitmapImage bmp) - { - elementInfos.Add(new CanvasElementInfo - { - Type = "Image", - SourcePath = bmp.UriSource?.LocalPath ?? "", - Left = InkCanvas.GetLeft(img), - Top = InkCanvas.GetTop(img), - Width = img.Width, - Height = img.Height, - Stretch = img.Stretch.ToString() - }); - } - } + CollectCanvasElementsMetadata(elementInfos); File.WriteAllText(Path.ChangeExtension(xmlPath, ".elements.json"), JsonConvert.SerializeObject(elementInfos, Newtonsoft.Json.Formatting.Indented)); // 异步上传到Dlass @@ -1266,6 +1280,10 @@ namespace Ink_Canvas InkCanvas.SetTop(img, info.Top); inkCanvas.Children.Add(img); } + else if (string.Equals(info.Type, "Pdf", StringComparison.OrdinalIgnoreCase) && File.Exists(info.SourcePath)) + { + Dispatcher.BeginInvoke(new Action(() => { _ = RestorePdfFromElementInfoAsync(info); }), DispatcherPriority.Loaded); + } } } } @@ -1416,6 +1434,10 @@ namespace Ink_Canvas InkCanvas.SetTop(img, info.Top); inkCanvas.Children.Add(img); } + else if (string.Equals(info.Type, "Pdf", StringComparison.OrdinalIgnoreCase) && File.Exists(info.SourcePath)) + { + Dispatcher.BeginInvoke(new Action(() => { _ = RestorePdfFromElementInfoAsync(info); }), DispatcherPriority.Loaded); + } } }