improve:pdf插入

This commit is contained in:
2026-04-05 18:42:06 +08:00
parent ea375a9ce6
commit bad05f77b5
6 changed files with 337 additions and 3 deletions
+1 -1
View File
@@ -102,7 +102,7 @@ namespace Ink_Canvas.Controls
NotifyPageNavigationStateChanged();
try
{
BitmapSource raw = await PdfWinRtHelper.RenderPageToBitmapSourceAsync(_pdfPath, pageIndex);
BitmapSource raw = await PdfDocumentRenderHelper.RenderPageToBitmapSourceAsync(_pdfPath, pageIndex);
if (raw == null)
return;
@@ -0,0 +1,62 @@
using System;
using System.Threading.Tasks;
using System.Windows.Media.Imaging;
namespace Ink_Canvas.Helpers
{
/// <summary>
/// PDF 页数与位图渲染:优先 <see cref="PdfWinRtHelper"/>Windows.Data.Pdf),失败或无效结果时使用 PDFtoImage(MIT) 备用。
/// </summary>
internal static class PdfDocumentRenderHelper
{
public static async Task<uint> GetPageCountAsync(string pdfPath)
{
uint winRt = 0;
try
{
winRt = await PdfWinRtHelper.GetPageCountAsync(pdfPath).ConfigureAwait(false);
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"PDF WinRT 获取页数失败,将尝试 PDFtoImage(MIT): {ex.Message}", LogHelper.LogType.Warning);
}
if (winRt > 0)
return winRt;
try
{
return await Task.Run(() => PdfToImageMitHelper.GetPageCount(pdfPath)).ConfigureAwait(false);
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"PDFtoImage(MIT) 获取页数失败: {ex.Message}", LogHelper.LogType.Warning);
return 0;
}
}
public static async Task<BitmapSource> RenderPageToBitmapSourceAsync(string pdfPath, uint pageIndex)
{
try
{
BitmapSource win = await PdfWinRtHelper.RenderPageToBitmapSourceAsync(pdfPath, pageIndex).ConfigureAwait(false);
if (win != null)
return win;
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"PDF WinRT 渲染失败,将尝试 PDFtoImage(MIT): {ex.Message}", LogHelper.LogType.Warning);
}
try
{
return await PdfToImageMitHelper.RenderPageToBitmapSourceAsync(pdfPath, pageIndex).ConfigureAwait(false);
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"PDFtoImage(MIT) 渲染失败: {ex.Message}", LogHelper.LogType.Warning);
return null;
}
}
}
}
+96
View File
@@ -0,0 +1,96 @@
using PDFtoImage;
using SkiaSharp;
using System;
using System.IO;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Media.Imaging;
namespace Ink_Canvas.Helpers
{
/// <summary>
/// 使用 NuGet「PDFtoImage」(MIT,基于 PDFium/SkiaSharp) 解析/渲染 PDF,作为 WinRT 不可用时的备用实现。
/// </summary>
internal static class PdfToImageMitHelper
{
public static uint GetPageCount(string pdfPath)
{
if (string.IsNullOrWhiteSpace(pdfPath) || !File.Exists(pdfPath))
return 0;
try
{
using (var fs = new FileStream(pdfPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
int n = Conversion.GetPageCount(fs, leaveOpen: true, password: null);
return n < 0 ? 0u : (uint)n;
}
}
catch
{
return 0;
}
}
/// <summary>
/// 在工作线程加载 PDF 页为 <see cref="SKBitmap"/>,在 UI 线程编码为 WPF <see cref="BitmapSource"/>。
/// </summary>
public static async Task<BitmapSource> RenderPageToBitmapSourceAsync(string pdfPath, uint pageIndex)
{
if (string.IsNullOrWhiteSpace(pdfPath) || !File.Exists(pdfPath))
return null;
int page = checked((int)pageIndex);
SKBitmap skBitmap = await Task.Run(() =>
{
try
{
using (var fs = new FileStream(pdfPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
return Conversion.ToImage(fs, System.Index.FromStart(page), leaveOpen: true, password: null, options: default);
}
}
catch
{
return null;
}
}).ConfigureAwait(false);
if (skBitmap == null)
return null;
try
{
if (Application.Current?.Dispatcher == null)
return null;
return await Application.Current.Dispatcher.InvokeAsync(() => EncodeSkBitmapToBitmapSource(skBitmap));
}
finally
{
skBitmap.Dispose();
}
}
private static BitmapSource EncodeSkBitmapToBitmapSource(SKBitmap bitmap)
{
using (var image = SKImage.FromBitmap(bitmap))
using (var data = image.Encode(SKEncodedImageFormat.Png, 100))
{
var ms = new MemoryStream();
data.SaveTo(ms);
ms.Position = 0;
var bi = new BitmapImage();
bi.BeginInit();
bi.StreamSource = ms;
bi.CacheOption = BitmapCacheOption.OnLoad;
bi.EndInit();
bi.Freeze();
ms.Dispose();
return bi;
}
}
}
}
+1
View File
@@ -141,6 +141,7 @@
<PackageReference Include="MdXaml" Version="1.27.0" />
<PackageReference Include="Microsoft.Office.Interop.PowerPoint" Version="15.0.4420.1018" />
<PackageReference Include="Microsoft.Windows.SDK.Contracts" Version="10.0.19041.2" />
<PackageReference Include="PDFtoImage" Version="5.1.0" />
<PackageReference Include="System.Runtime.WindowsRuntime" Version="4.7.0" />
<PackageReference Include="MicrosoftOfficeCore" Version="15.0.0" />
<PackageReference Include="Microsoft.Toolkit.Uwp.Notifications" Version="7.1.3" />
@@ -1007,7 +1007,7 @@ namespace Ink_Canvas
string newFilePath = Path.Combine(savePath, timestamp + ".pdf");
await Task.Run(() => File.Copy(filePath, newFilePath, true));
uint pageCount = await PdfWinRtHelper.GetPageCountAsync(newFilePath);
uint pageCount = await PdfDocumentRenderHelper.GetPageCountAsync(newFilePath);
if (pageCount == 0)
{
ShowNotification("无法打开 PDF(可能已加密、损坏或不支持)。");
@@ -1037,7 +1037,7 @@ namespace Ink_Canvas
try
{
uint pageCount = await PdfWinRtHelper.GetPageCountAsync(info.SourcePath);
uint pageCount = await PdfDocumentRenderHelper.GetPageCountAsync(info.SourcePath);
if (pageCount == 0) return;
bool compress = isLoaded && Settings.Canvas.IsCompressPicturesUploaded;
+175
View File
@@ -157,6 +157,21 @@
"Microsoft.Win32.Registry": "5.0.0"
}
},
"PDFtoImage": {
"type": "Direct",
"requested": "[5.1.0, )",
"resolved": "5.1.0",
"contentHash": "QbGA2pdMCdQFI0MpXXDD7teGJsOR3ic9T8iGv3hXTtyMSjJkVgFDKRxRU9Ri31DbkkpvY7azzNeUTWdf5AqPZg==",
"dependencies": {
"SkiaSharp": "3.119.0",
"SkiaSharp.NativeAssets.Linux.NoDependencies": "3.119.0",
"SkiaSharp.NativeAssets.Win32": "3.119.0",
"SkiaSharp.NativeAssets.macOS": "3.119.0",
"bblanchon.PDFium.Linux": "137.0.7149",
"bblanchon.PDFium.Win32": "137.0.7149",
"bblanchon.PDFium.macOS": "137.0.7149"
}
},
"Sentry": {
"type": "Direct",
"requested": "[6.2.0, )",
@@ -190,6 +205,21 @@
"resolved": "6.3.0.90",
"contentHash": "WVTb5MxwGqKdeasd3nG5udlV4t6OpvkFanziwI133K0/QJ5FvZmfzRQgpAjGTJhQfIA8GP7AzKQ3sTY9JOFk8Q=="
},
"bblanchon.PDFium.Linux": {
"type": "Transitive",
"resolved": "137.0.7149",
"contentHash": "tT2GeyKE39ci3THZ/ddzhvZ3efgfCdEsZtDfEH+kDV1dfl2hxFeZesdTcRnxj3hp/ScnxTNJNa0RZtwOwc0I3g=="
},
"bblanchon.PDFium.macOS": {
"type": "Transitive",
"resolved": "137.0.7149",
"contentHash": "OXZJhlJ/jynL5dz9/OJ65UFCIqZBepdyd84xE11AAWgG6UPERi2p4tEmmIAbloZ+aRBtaCRWNk5pgyF2WDe7vQ=="
},
"bblanchon.PDFium.Win32": {
"type": "Transitive",
"resolved": "137.0.7149",
"contentHash": "M3C2UCvKD1X6hJ/VB6arBMhI91OYHzybWMAOVFUKuEpfTR1nKfbYa/1dNVHKPmc8ST0SAYeVOlkv+XlJrsXy/Q=="
},
"Fody": {
"type": "Transitive",
"resolved": "6.8.2",
@@ -240,6 +270,31 @@
"resolved": "4.0.0",
"contentHash": "5HKzttVKWeKoDQKJd3+J7Dy1MW6gbNNYfftkVufe2ddFQD0kXjnT1IN3ZJBfF6QVEQmHpQSp+/PT7Jo2YyHFcw=="
},
"SkiaSharp": {
"type": "Transitive",
"resolved": "3.119.0",
"contentHash": "gR9yVoOta2Mc1Rxt15LD65AckfHMfwjIs/3kkD59C9bT2nYYISsE6uz3t4aMPNHA6CgsIL0Ssn+jE5OVilZ1yw==",
"dependencies": {
"SkiaSharp.NativeAssets.Win32": "3.119.0",
"SkiaSharp.NativeAssets.macOS": "3.119.0",
"System.Memory": "4.5.5"
}
},
"SkiaSharp.NativeAssets.Linux.NoDependencies": {
"type": "Transitive",
"resolved": "3.119.0",
"contentHash": "e92vdqf1VOETPjy1T67Fs1zPxfGMM1nbrpt69GM5foXSI/iIbq6L9avPz/bl/DbWtb81D0yF/NKjRmXuOZoLcg=="
},
"SkiaSharp.NativeAssets.macOS": {
"type": "Transitive",
"resolved": "3.119.0",
"contentHash": "YE1vNn0Nyw2PWtv7hw1PYkKJO0itFiQp9vSqGppZUKzQJqwp28a2jgdCMPfYtOiR8KCnDgZqQoynqJRRaE2ZVg=="
},
"SkiaSharp.NativeAssets.Win32": {
"type": "Transitive",
"resolved": "3.119.0",
"contentHash": "IwC9yx36lOdXVT2DjgmWHl1qkVspfj8ctd4+li8CNnvqdfaTolXCOh6TLznURcPAvzatx9K/tLOB7zT6T8EA9w=="
},
"System.Buffers": {
"type": "Transitive",
"resolved": "4.5.1",
@@ -351,6 +406,21 @@
}
},
".NETFramework,Version=v4.7.2/win": {
"bblanchon.PDFium.Linux": {
"type": "Transitive",
"resolved": "137.0.7149",
"contentHash": "tT2GeyKE39ci3THZ/ddzhvZ3efgfCdEsZtDfEH+kDV1dfl2hxFeZesdTcRnxj3hp/ScnxTNJNa0RZtwOwc0I3g=="
},
"bblanchon.PDFium.macOS": {
"type": "Transitive",
"resolved": "137.0.7149",
"contentHash": "OXZJhlJ/jynL5dz9/OJ65UFCIqZBepdyd84xE11AAWgG6UPERi2p4tEmmIAbloZ+aRBtaCRWNk5pgyF2WDe7vQ=="
},
"bblanchon.PDFium.Win32": {
"type": "Transitive",
"resolved": "137.0.7149",
"contentHash": "M3C2UCvKD1X6hJ/VB6arBMhI91OYHzybWMAOVFUKuEpfTR1nKfbYa/1dNVHKPmc8ST0SAYeVOlkv+XlJrsXy/Q=="
},
"Microsoft.Win32.Registry": {
"type": "Transitive",
"resolved": "5.0.0",
@@ -360,6 +430,21 @@
"System.Security.Principal.Windows": "5.0.0"
}
},
"SkiaSharp.NativeAssets.Linux.NoDependencies": {
"type": "Transitive",
"resolved": "3.119.0",
"contentHash": "e92vdqf1VOETPjy1T67Fs1zPxfGMM1nbrpt69GM5foXSI/iIbq6L9avPz/bl/DbWtb81D0yF/NKjRmXuOZoLcg=="
},
"SkiaSharp.NativeAssets.macOS": {
"type": "Transitive",
"resolved": "3.119.0",
"contentHash": "YE1vNn0Nyw2PWtv7hw1PYkKJO0itFiQp9vSqGppZUKzQJqwp28a2jgdCMPfYtOiR8KCnDgZqQoynqJRRaE2ZVg=="
},
"SkiaSharp.NativeAssets.Win32": {
"type": "Transitive",
"resolved": "3.119.0",
"contentHash": "IwC9yx36lOdXVT2DjgmWHl1qkVspfj8ctd4+li8CNnvqdfaTolXCOh6TLznURcPAvzatx9K/tLOB7zT6T8EA9w=="
},
"System.Runtime.InteropServices.RuntimeInformation": {
"type": "Transitive",
"resolved": "4.3.0",
@@ -380,6 +465,21 @@
}
},
".NETFramework,Version=v4.7.2/win-arm64": {
"bblanchon.PDFium.Linux": {
"type": "Transitive",
"resolved": "137.0.7149",
"contentHash": "tT2GeyKE39ci3THZ/ddzhvZ3efgfCdEsZtDfEH+kDV1dfl2hxFeZesdTcRnxj3hp/ScnxTNJNa0RZtwOwc0I3g=="
},
"bblanchon.PDFium.macOS": {
"type": "Transitive",
"resolved": "137.0.7149",
"contentHash": "OXZJhlJ/jynL5dz9/OJ65UFCIqZBepdyd84xE11AAWgG6UPERi2p4tEmmIAbloZ+aRBtaCRWNk5pgyF2WDe7vQ=="
},
"bblanchon.PDFium.Win32": {
"type": "Transitive",
"resolved": "137.0.7149",
"contentHash": "M3C2UCvKD1X6hJ/VB6arBMhI91OYHzybWMAOVFUKuEpfTR1nKfbYa/1dNVHKPmc8ST0SAYeVOlkv+XlJrsXy/Q=="
},
"Microsoft.Win32.Registry": {
"type": "Transitive",
"resolved": "5.0.0",
@@ -389,6 +489,21 @@
"System.Security.Principal.Windows": "5.0.0"
}
},
"SkiaSharp.NativeAssets.Linux.NoDependencies": {
"type": "Transitive",
"resolved": "3.119.0",
"contentHash": "e92vdqf1VOETPjy1T67Fs1zPxfGMM1nbrpt69GM5foXSI/iIbq6L9avPz/bl/DbWtb81D0yF/NKjRmXuOZoLcg=="
},
"SkiaSharp.NativeAssets.macOS": {
"type": "Transitive",
"resolved": "3.119.0",
"contentHash": "YE1vNn0Nyw2PWtv7hw1PYkKJO0itFiQp9vSqGppZUKzQJqwp28a2jgdCMPfYtOiR8KCnDgZqQoynqJRRaE2ZVg=="
},
"SkiaSharp.NativeAssets.Win32": {
"type": "Transitive",
"resolved": "3.119.0",
"contentHash": "IwC9yx36lOdXVT2DjgmWHl1qkVspfj8ctd4+li8CNnvqdfaTolXCOh6TLznURcPAvzatx9K/tLOB7zT6T8EA9w=="
},
"System.Runtime.InteropServices.RuntimeInformation": {
"type": "Transitive",
"resolved": "4.3.0",
@@ -409,6 +524,21 @@
}
},
".NETFramework,Version=v4.7.2/win-x64": {
"bblanchon.PDFium.Linux": {
"type": "Transitive",
"resolved": "137.0.7149",
"contentHash": "tT2GeyKE39ci3THZ/ddzhvZ3efgfCdEsZtDfEH+kDV1dfl2hxFeZesdTcRnxj3hp/ScnxTNJNa0RZtwOwc0I3g=="
},
"bblanchon.PDFium.macOS": {
"type": "Transitive",
"resolved": "137.0.7149",
"contentHash": "OXZJhlJ/jynL5dz9/OJ65UFCIqZBepdyd84xE11AAWgG6UPERi2p4tEmmIAbloZ+aRBtaCRWNk5pgyF2WDe7vQ=="
},
"bblanchon.PDFium.Win32": {
"type": "Transitive",
"resolved": "137.0.7149",
"contentHash": "M3C2UCvKD1X6hJ/VB6arBMhI91OYHzybWMAOVFUKuEpfTR1nKfbYa/1dNVHKPmc8ST0SAYeVOlkv+XlJrsXy/Q=="
},
"Microsoft.Win32.Registry": {
"type": "Transitive",
"resolved": "5.0.0",
@@ -418,6 +548,21 @@
"System.Security.Principal.Windows": "5.0.0"
}
},
"SkiaSharp.NativeAssets.Linux.NoDependencies": {
"type": "Transitive",
"resolved": "3.119.0",
"contentHash": "e92vdqf1VOETPjy1T67Fs1zPxfGMM1nbrpt69GM5foXSI/iIbq6L9avPz/bl/DbWtb81D0yF/NKjRmXuOZoLcg=="
},
"SkiaSharp.NativeAssets.macOS": {
"type": "Transitive",
"resolved": "3.119.0",
"contentHash": "YE1vNn0Nyw2PWtv7hw1PYkKJO0itFiQp9vSqGppZUKzQJqwp28a2jgdCMPfYtOiR8KCnDgZqQoynqJRRaE2ZVg=="
},
"SkiaSharp.NativeAssets.Win32": {
"type": "Transitive",
"resolved": "3.119.0",
"contentHash": "IwC9yx36lOdXVT2DjgmWHl1qkVspfj8ctd4+li8CNnvqdfaTolXCOh6TLznURcPAvzatx9K/tLOB7zT6T8EA9w=="
},
"System.Runtime.InteropServices.RuntimeInformation": {
"type": "Transitive",
"resolved": "4.3.0",
@@ -438,6 +583,21 @@
}
},
".NETFramework,Version=v4.7.2/win-x86": {
"bblanchon.PDFium.Linux": {
"type": "Transitive",
"resolved": "137.0.7149",
"contentHash": "tT2GeyKE39ci3THZ/ddzhvZ3efgfCdEsZtDfEH+kDV1dfl2hxFeZesdTcRnxj3hp/ScnxTNJNa0RZtwOwc0I3g=="
},
"bblanchon.PDFium.macOS": {
"type": "Transitive",
"resolved": "137.0.7149",
"contentHash": "OXZJhlJ/jynL5dz9/OJ65UFCIqZBepdyd84xE11AAWgG6UPERi2p4tEmmIAbloZ+aRBtaCRWNk5pgyF2WDe7vQ=="
},
"bblanchon.PDFium.Win32": {
"type": "Transitive",
"resolved": "137.0.7149",
"contentHash": "M3C2UCvKD1X6hJ/VB6arBMhI91OYHzybWMAOVFUKuEpfTR1nKfbYa/1dNVHKPmc8ST0SAYeVOlkv+XlJrsXy/Q=="
},
"Microsoft.Win32.Registry": {
"type": "Transitive",
"resolved": "5.0.0",
@@ -447,6 +607,21 @@
"System.Security.Principal.Windows": "5.0.0"
}
},
"SkiaSharp.NativeAssets.Linux.NoDependencies": {
"type": "Transitive",
"resolved": "3.119.0",
"contentHash": "e92vdqf1VOETPjy1T67Fs1zPxfGMM1nbrpt69GM5foXSI/iIbq6L9avPz/bl/DbWtb81D0yF/NKjRmXuOZoLcg=="
},
"SkiaSharp.NativeAssets.macOS": {
"type": "Transitive",
"resolved": "3.119.0",
"contentHash": "YE1vNn0Nyw2PWtv7hw1PYkKJO0itFiQp9vSqGppZUKzQJqwp28a2jgdCMPfYtOiR8KCnDgZqQoynqJRRaE2ZVg=="
},
"SkiaSharp.NativeAssets.Win32": {
"type": "Transitive",
"resolved": "3.119.0",
"contentHash": "IwC9yx36lOdXVT2DjgmWHl1qkVspfj8ctd4+li8CNnvqdfaTolXCOh6TLznURcPAvzatx9K/tLOB7zT6T8EA9w=="
},
"System.Runtime.InteropServices.RuntimeInformation": {
"type": "Transitive",
"resolved": "4.3.0",