add:pdf插入

This commit is contained in:
2026-04-05 18:06:21 +08:00
parent cffedb8cb7
commit ea74592e89
6 changed files with 117 additions and 47 deletions
+7 -7
View File
@@ -20,7 +20,6 @@ namespace Ink_Canvas.Controls
private uint _currentIndex;
private bool _compressLargePictures;
private bool _isPagingBusy;
private bool _layoutSizeLocked;
/// <summary>页码或可翻页状态变化(用于更新侧栏)。</summary>
public event EventHandler PageNavigationStateChanged;
@@ -42,14 +41,18 @@ namespace Ink_Canvas.Controls
}
/// <summary>
/// 初始化并显示第一页;由 MainWindow 在 UI 线程创建后调用。
/// 初始化并显示指定页;由 MainWindow 在 UI 线程创建后调用。
/// </summary>
public async Task InitializeAsync(string pdfFilePath, uint pageCount, bool compressLargePictures)
/// <param name="initialPageIndex">从 0 开始的页码,超出范围时夹紧到合法区间。</param>
public async Task InitializeAsync(string pdfFilePath, uint pageCount, bool compressLargePictures, uint initialPageIndex = 0)
{
_pdfPath = pdfFilePath ?? throw new ArgumentNullException(nameof(pdfFilePath));
_pageCount = pageCount;
_compressLargePictures = compressLargePictures;
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;
}
}
finally
{
-1
View File
@@ -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;
+12 -1
View File
@@ -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);
}
}
}));
}
@@ -1021,6 +1021,46 @@ namespace Ink_Canvas
}
}
/// <summary>从保存的 <see cref="CanvasElementInfo"/> 恢复 PDF(与打开墨迹时的图片恢复流程一致,不单独写入时间轴)。</summary>
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
@@ -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;
+55 -33
View File
@@ -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
/// <summary>PDF 当前页(从 0 开始),仅 Type == Pdf 时有效。</summary>
public int? PdfCurrentPage { get; set; }
/// <summary>保存时的 PDF 总页数,用于校验;仅 Type == Pdf 时有效。</summary>
public int? PdfPageCount { get; set; }
}
public partial class MainWindow : Window
{
/// <summary>收集画布上图片与 PDF 的元数据,写入 .elements.json(与墨迹文件同路径)。</summary>
private void CollectCanvasElementsMetadata(List<CanvasElementInfo> 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
});
}
}
}
/// <summary>
/// 保存墨迹的鼠标释放事件处理
/// </summary>
@@ -419,22 +463,7 @@ namespace Ink_Canvas
// 保存元素信息
var elementInfos = new List<CanvasElementInfo>();
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<CanvasElementInfo>();
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);
}
}
}