add:pdf插入
This commit is contained in:
@@ -0,0 +1,136 @@
|
|||||||
|
using Ink_Canvas.Helpers;
|
||||||
|
using System;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Controls;
|
||||||
|
using System.Windows.Media;
|
||||||
|
using System.Windows.Media.Imaging;
|
||||||
|
|
||||||
|
namespace Ink_Canvas.Controls
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 画布上的多页 PDF:仅显示当前页;翻页与页码由主窗口 PDF 侧栏控制(无 XAML 文件)。
|
||||||
|
/// </summary>
|
||||||
|
public class PdfEmbeddedView : UserControl
|
||||||
|
{
|
||||||
|
private readonly Image _pageImage;
|
||||||
|
|
||||||
|
private string _pdfPath;
|
||||||
|
private uint _pageCount;
|
||||||
|
private uint _currentIndex;
|
||||||
|
private bool _compressLargePictures;
|
||||||
|
private bool _isPagingBusy;
|
||||||
|
private bool _layoutSizeLocked;
|
||||||
|
|
||||||
|
/// <summary>页码或可翻页状态变化(用于更新侧栏)。</summary>
|
||||||
|
public event EventHandler PageNavigationStateChanged;
|
||||||
|
|
||||||
|
public PdfEmbeddedView()
|
||||||
|
{
|
||||||
|
MinWidth = 80;
|
||||||
|
MinHeight = 60;
|
||||||
|
|
||||||
|
var grid = new Grid { ClipToBounds = true };
|
||||||
|
_pageImage = new Image
|
||||||
|
{
|
||||||
|
Stretch = Stretch.Uniform,
|
||||||
|
HorizontalAlignment = HorizontalAlignment.Center,
|
||||||
|
VerticalAlignment = VerticalAlignment.Center
|
||||||
|
};
|
||||||
|
grid.Children.Add(_pageImage);
|
||||||
|
Content = grid;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 初始化并显示第一页;由 MainWindow 在 UI 线程创建后调用。
|
||||||
|
/// </summary>
|
||||||
|
public async Task InitializeAsync(string pdfFilePath, uint pageCount, bool compressLargePictures)
|
||||||
|
{
|
||||||
|
_pdfPath = pdfFilePath ?? throw new ArgumentNullException(nameof(pdfFilePath));
|
||||||
|
_pageCount = pageCount;
|
||||||
|
_compressLargePictures = compressLargePictures;
|
||||||
|
_currentIndex = 0;
|
||||||
|
|
||||||
|
await ShowPageAsync(_currentIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
public string PdfPath => _pdfPath;
|
||||||
|
|
||||||
|
public uint PageCount => _pageCount;
|
||||||
|
|
||||||
|
public uint CurrentPageIndex => _currentIndex;
|
||||||
|
|
||||||
|
public string PageLabelText => _pageCount == 0 ? "" : $"{_currentIndex + 1} / {_pageCount}";
|
||||||
|
|
||||||
|
public bool CanGoPrevious => !_isPagingBusy && _pageCount > 1 && _currentIndex > 0;
|
||||||
|
|
||||||
|
public bool CanGoNext => !_isPagingBusy && _pageCount > 1 && _currentIndex < _pageCount - 1;
|
||||||
|
|
||||||
|
public async Task GoToPreviousPageAsync()
|
||||||
|
{
|
||||||
|
await GoRelativeAsync(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task GoToNextPageAsync()
|
||||||
|
{
|
||||||
|
await GoRelativeAsync(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void NotifyPageNavigationStateChanged()
|
||||||
|
{
|
||||||
|
PageNavigationStateChanged?.Invoke(this, EventArgs.Empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task GoRelativeAsync(int delta)
|
||||||
|
{
|
||||||
|
if (_isPagingBusy || _pageCount <= 1)
|
||||||
|
return;
|
||||||
|
int next = (int)_currentIndex + delta;
|
||||||
|
if (next < 0 || next >= _pageCount)
|
||||||
|
return;
|
||||||
|
_currentIndex = (uint)next;
|
||||||
|
await ShowPageAsync(_currentIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task ShowPageAsync(uint pageIndex)
|
||||||
|
{
|
||||||
|
_isPagingBusy = true;
|
||||||
|
NotifyPageNavigationStateChanged();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
BitmapSource raw = await PdfWinRtHelper.RenderPageToBitmapSourceAsync(_pdfPath, pageIndex);
|
||||||
|
if (raw == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
BitmapSource display = ApplyCompressionIfNeeded(raw);
|
||||||
|
_pageImage.Source = display;
|
||||||
|
if (!_layoutSizeLocked)
|
||||||
|
{
|
||||||
|
Width = display.PixelWidth;
|
||||||
|
Height = display.PixelHeight;
|
||||||
|
_layoutSizeLocked = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
_isPagingBusy = false;
|
||||||
|
NotifyPageNavigationStateChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private BitmapSource ApplyCompressionIfNeeded(BitmapSource rendered)
|
||||||
|
{
|
||||||
|
int width = rendered.PixelWidth;
|
||||||
|
int height = rendered.PixelHeight;
|
||||||
|
if (_compressLargePictures && (width > 1920 || height > 1080))
|
||||||
|
{
|
||||||
|
double scaleX = 1920.0 / width;
|
||||||
|
double scaleY = 1080.0 / height;
|
||||||
|
double scale = Math.Min(scaleX, scaleY);
|
||||||
|
return new TransformedBitmap(rendered, new ScaleTransform(scale, scale));
|
||||||
|
}
|
||||||
|
|
||||||
|
return rendered;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,80 @@
|
|||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Runtime.InteropServices.WindowsRuntime;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Media.Imaging;
|
||||||
|
using Windows.Data.Pdf;
|
||||||
|
using Windows.Storage;
|
||||||
|
using Windows.Storage.Streams;
|
||||||
|
|
||||||
|
namespace Ink_Canvas.Helpers
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 使用 Windows.Data.Pdf(WinRT)将 PDF 页渲染为 WPF 可用的位图。
|
||||||
|
/// </summary>
|
||||||
|
internal static class PdfWinRtHelper
|
||||||
|
{
|
||||||
|
public static async Task<uint> GetPageCountAsync(string pdfPath)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(pdfPath) || !File.Exists(pdfPath))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
var file = await StorageFile.GetFileFromPathAsync(pdfPath).AsTask();
|
||||||
|
var doc = await PdfDocument.LoadFromFileAsync(file).AsTask();
|
||||||
|
if (doc.IsPasswordProtected)
|
||||||
|
return 0;
|
||||||
|
return doc.PageCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async Task<BitmapSource> RenderPageToBitmapSourceAsync(string pdfPath, uint pageIndex)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(pdfPath) || !File.Exists(pdfPath))
|
||||||
|
return null;
|
||||||
|
|
||||||
|
var file = await StorageFile.GetFileFromPathAsync(pdfPath).AsTask();
|
||||||
|
var doc = await PdfDocument.LoadFromFileAsync(file).AsTask();
|
||||||
|
if (doc.IsPasswordProtected)
|
||||||
|
return null;
|
||||||
|
if (pageIndex >= doc.PageCount)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
var page = doc.GetPage(pageIndex);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using (var ras = new InMemoryRandomAccessStream())
|
||||||
|
{
|
||||||
|
await page.RenderToStreamAsync(ras).AsTask();
|
||||||
|
ras.Seek(0);
|
||||||
|
|
||||||
|
var ms = new MemoryStream();
|
||||||
|
using (var netStream = ras.AsStreamForRead())
|
||||||
|
netStream.CopyTo(ms);
|
||||||
|
ms.Position = 0;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return await Application.Current.Dispatcher.InvokeAsync(() =>
|
||||||
|
{
|
||||||
|
var bi = new BitmapImage();
|
||||||
|
bi.BeginInit();
|
||||||
|
bi.StreamSource = ms;
|
||||||
|
bi.CacheOption = BitmapCacheOption.OnLoad;
|
||||||
|
bi.EndInit();
|
||||||
|
bi.Freeze();
|
||||||
|
return (BitmapSource)bi;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
ms.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
(page as IDisposable)?.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -141,6 +141,7 @@
|
|||||||
<PackageReference Include="MdXaml" Version="1.27.0" />
|
<PackageReference Include="MdXaml" Version="1.27.0" />
|
||||||
<PackageReference Include="Microsoft.Office.Interop.PowerPoint" Version="15.0.4420.1018" />
|
<PackageReference Include="Microsoft.Office.Interop.PowerPoint" Version="15.0.4420.1018" />
|
||||||
<PackageReference Include="Microsoft.Windows.SDK.Contracts" Version="10.0.19041.2" />
|
<PackageReference Include="Microsoft.Windows.SDK.Contracts" Version="10.0.19041.2" />
|
||||||
|
<PackageReference Include="System.Runtime.WindowsRuntime" Version="4.7.0" />
|
||||||
<PackageReference Include="MicrosoftOfficeCore" Version="15.0.0" />
|
<PackageReference Include="MicrosoftOfficeCore" Version="15.0.0" />
|
||||||
<PackageReference Include="Microsoft.Toolkit.Uwp.Notifications" Version="7.1.3" />
|
<PackageReference Include="Microsoft.Toolkit.Uwp.Notifications" Version="7.1.3" />
|
||||||
<PackageReference Include="Microsoft.International.Converters.PinYinConverter" Version="1.0.0" />
|
<PackageReference Include="Microsoft.International.Converters.PinYinConverter" Version="1.0.0" />
|
||||||
|
|||||||
@@ -4948,6 +4948,109 @@
|
|||||||
</Viewbox>
|
</Viewbox>
|
||||||
</Border>
|
</Border>
|
||||||
|
|
||||||
|
<Border Name="BorderPdfPageSidebar"
|
||||||
|
HorizontalAlignment="Left"
|
||||||
|
VerticalAlignment="Top"
|
||||||
|
Margin="0,0,0,0"
|
||||||
|
Width="58"
|
||||||
|
CornerRadius="10"
|
||||||
|
Background="{DynamicResource FloatBarBackground}"
|
||||||
|
BorderBrush="{DynamicResource FloatBarBorderBrush}"
|
||||||
|
BorderThickness="1"
|
||||||
|
SnapsToDevicePixels="True"
|
||||||
|
Visibility="Collapsed"
|
||||||
|
Panel.ZIndex="1001">
|
||||||
|
<Border.Resources>
|
||||||
|
<Style x:Key="PdfSidebarNavButtonStyle" TargetType="Border">
|
||||||
|
<Setter Property="Width" Value="42" />
|
||||||
|
<Setter Property="Height" Value="38" />
|
||||||
|
<Setter Property="CornerRadius" Value="8" />
|
||||||
|
<Setter Property="BorderThickness" Value="1" />
|
||||||
|
<Setter Property="BorderBrush" Value="{DynamicResource FloatBarForeground}" />
|
||||||
|
<Setter Property="Cursor" Value="Hand" />
|
||||||
|
<Setter Property="SnapsToDevicePixels" Value="True" />
|
||||||
|
<Setter Property="Background">
|
||||||
|
<Setter.Value>
|
||||||
|
<SolidColorBrush Color="White" Opacity="0.10" />
|
||||||
|
</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
<Style.Triggers>
|
||||||
|
<Trigger Property="IsMouseOver" Value="True">
|
||||||
|
<Setter Property="Background">
|
||||||
|
<Setter.Value>
|
||||||
|
<SolidColorBrush Color="White" Opacity="0.22" />
|
||||||
|
</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
</Trigger>
|
||||||
|
</Style.Triggers>
|
||||||
|
</Style>
|
||||||
|
</Border.Resources>
|
||||||
|
<Grid>
|
||||||
|
<ikw:SimpleStackPanel VerticalAlignment="Center"
|
||||||
|
HorizontalAlignment="Center"
|
||||||
|
Spacing="10"
|
||||||
|
Margin="0,8,0,8">
|
||||||
|
<TextBlock Text="PDF"
|
||||||
|
FontSize="11"
|
||||||
|
FontWeight="SemiBold"
|
||||||
|
HorizontalAlignment="Center"
|
||||||
|
Foreground="{DynamicResource FloatBarForeground}"
|
||||||
|
Opacity="0.9" />
|
||||||
|
<Border CornerRadius="8"
|
||||||
|
Padding="6,8"
|
||||||
|
BorderThickness="1"
|
||||||
|
BorderBrush="{DynamicResource FloatBarForeground}"
|
||||||
|
SnapsToDevicePixels="True">
|
||||||
|
<Border.Background>
|
||||||
|
<SolidColorBrush Color="White" Opacity="0.08" />
|
||||||
|
</Border.Background>
|
||||||
|
<TextBlock Name="TextBlockPdfSidebarPageLabel"
|
||||||
|
Text="— / —"
|
||||||
|
FontSize="12"
|
||||||
|
FontWeight="SemiBold"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
HorizontalAlignment="Center"
|
||||||
|
TextAlignment="Center"
|
||||||
|
Foreground="{DynamicResource FloatBarForeground}"
|
||||||
|
Opacity="0.55" />
|
||||||
|
</Border>
|
||||||
|
<Border Name="BorderPdfSidebarPagePrev"
|
||||||
|
Style="{StaticResource PdfSidebarNavButtonStyle}"
|
||||||
|
Opacity="0.35"
|
||||||
|
IsHitTestVisible="False"
|
||||||
|
MouseDown="Border_MouseDown"
|
||||||
|
MouseUp="BorderPdfSidebarPagePrev_MouseUp">
|
||||||
|
<TextBlock Text="‹"
|
||||||
|
FontSize="20"
|
||||||
|
FontWeight="SemiBold"
|
||||||
|
HorizontalAlignment="Center"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Margin="0,-2,0,0"
|
||||||
|
Foreground="{DynamicResource FloatBarForeground}" />
|
||||||
|
</Border>
|
||||||
|
<Border Name="BorderPdfSidebarPageNext"
|
||||||
|
Style="{StaticResource PdfSidebarNavButtonStyle}"
|
||||||
|
Opacity="0.35"
|
||||||
|
IsHitTestVisible="False"
|
||||||
|
MouseDown="Border_MouseDown"
|
||||||
|
MouseUp="BorderPdfSidebarPageNext_MouseUp">
|
||||||
|
<TextBlock Text="›"
|
||||||
|
FontSize="20"
|
||||||
|
FontWeight="SemiBold"
|
||||||
|
HorizontalAlignment="Center"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Margin="0,-2,0,0"
|
||||||
|
Foreground="{DynamicResource FloatBarForeground}" />
|
||||||
|
</Border>
|
||||||
|
<TextBlock Text="翻页"
|
||||||
|
FontSize="9"
|
||||||
|
HorizontalAlignment="Center"
|
||||||
|
Foreground="{DynamicResource FloatBarForeground}"
|
||||||
|
Opacity="0.65" />
|
||||||
|
</ikw:SimpleStackPanel>
|
||||||
|
</Grid>
|
||||||
|
</Border>
|
||||||
|
|
||||||
<!-- 图片缩放选择点 -->
|
<!-- 图片缩放选择点 -->
|
||||||
<Canvas Name="ImageResizeHandlesCanvas"
|
<Canvas Name="ImageResizeHandlesCanvas"
|
||||||
Visibility="Collapsed"
|
Visibility="Collapsed"
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
using Ink_Canvas.Controls;
|
||||||
using Ink_Canvas.Helpers;
|
using Ink_Canvas.Helpers;
|
||||||
using Microsoft.Win32;
|
using Microsoft.Win32;
|
||||||
using System;
|
using System;
|
||||||
@@ -56,48 +57,48 @@ namespace Ink_Canvas
|
|||||||
private async void BtnImageInsert_Click(object sender, RoutedEventArgs e)
|
private async void BtnImageInsert_Click(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
OpenFileDialog openFileDialog = new OpenFileDialog();
|
OpenFileDialog openFileDialog = new OpenFileDialog();
|
||||||
openFileDialog.Filter = "Image files (*.jpg; *.jpeg; *.png; *.bmp)|*.jpg;*.jpeg;*.png;*.bmp";
|
openFileDialog.Filter = "图片与 PDF|*.jpg;*.jpeg;*.png;*.bmp;*.gif;*.pdf|图片文件|*.jpg;*.jpeg;*.png;*.bmp;*.gif|PDF|*.pdf";
|
||||||
|
|
||||||
if (openFileDialog.ShowDialog() == true)
|
if (openFileDialog.ShowDialog() == true)
|
||||||
{
|
{
|
||||||
string filePath = openFileDialog.FileName;
|
string filePath = openFileDialog.FileName;
|
||||||
|
|
||||||
Image image = await CreateAndCompressImageAsync(filePath);
|
FrameworkElement element = await CreateAndCompressImageAsync(filePath);
|
||||||
|
|
||||||
if (image != null)
|
if (element != null)
|
||||||
{
|
{
|
||||||
string timestamp = "img_" + DateTime.Now.ToString("yyyyMMdd_HH_mm_ss_fff");
|
string timestamp = "img_" + DateTime.Now.ToString("yyyyMMdd_HH_mm_ss_fff");
|
||||||
image.Name = timestamp;
|
element.Name = timestamp;
|
||||||
|
|
||||||
// 设置图片属性,避免被InkCanvas选择系统处理
|
// 设置图片属性,避免被InkCanvas选择系统处理
|
||||||
image.IsHitTestVisible = true;
|
element.IsHitTestVisible = true;
|
||||||
image.Focusable = false;
|
element.Focusable = false;
|
||||||
|
|
||||||
// 初始化InkCanvas选择设置
|
// 初始化InkCanvas选择设置
|
||||||
InitializeInkCanvasSelectionSettings();
|
InitializeInkCanvasSelectionSettings();
|
||||||
|
|
||||||
// 先添加到画布
|
// 先添加到画布
|
||||||
inkCanvas.Children.Add(image);
|
inkCanvas.Children.Add(element);
|
||||||
|
|
||||||
// 等待图片加载完成后再进行后续处理
|
// 等待图片加载完成后再进行后续处理
|
||||||
image.Loaded += (s, args) =>
|
element.Loaded += (s, args) =>
|
||||||
{
|
{
|
||||||
Dispatcher.BeginInvoke(new Action(() =>
|
Dispatcher.BeginInvoke(new Action(() =>
|
||||||
{
|
{
|
||||||
// 初始化TransformGroup
|
// 初始化TransformGroup
|
||||||
InitializeElementTransform(image);
|
InitializeElementTransform(element);
|
||||||
|
|
||||||
// 居中缩放
|
// 居中缩放
|
||||||
CenterAndScaleElement(image);
|
CenterAndScaleElement(element);
|
||||||
|
|
||||||
// 最后绑定事件处理器
|
// 最后绑定事件处理器
|
||||||
BindElementEvents(image);
|
BindElementEvents(element);
|
||||||
|
|
||||||
LogHelper.WriteLogToFile($"图片插入完成: {image.Name}");
|
LogHelper.WriteLogToFile($"图片插入完成: {element.Name}");
|
||||||
}), DispatcherPriority.Loaded);
|
}), DispatcherPriority.Loaded);
|
||||||
};
|
};
|
||||||
|
|
||||||
timeMachine.CommitElementInsertHistory(image);
|
timeMachine.CommitElementInsertHistory(element);
|
||||||
|
|
||||||
// 插入图片后切换到选择模式并刷新浮动栏高光显示
|
// 插入图片后切换到选择模式并刷新浮动栏高光显示
|
||||||
SetCurrentToolMode(InkCanvasEditingMode.Select);
|
SetCurrentToolMode(InkCanvasEditingMode.Select);
|
||||||
@@ -270,13 +271,13 @@ namespace Ink_Canvas
|
|||||||
ApplyMouseDragTransform(element, currentPoint, dragStartPoint);
|
ApplyMouseDragTransform(element, currentPoint, dragStartPoint);
|
||||||
|
|
||||||
// 如果是图片元素,更新工具栏位置
|
// 如果是图片元素,更新工具栏位置
|
||||||
if (element is Image && BorderImageSelectionControl?.Visibility == Visibility.Visible)
|
if (IsBitmapLikeCanvasElement(element) && BorderImageSelectionControl?.Visibility == Visibility.Visible)
|
||||||
{
|
{
|
||||||
UpdateImageSelectionToolbarPosition(element);
|
UpdateImageSelectionToolbarPosition(element);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 如果是图片元素,更新选择点位置
|
// 如果是图片元素,更新选择点位置
|
||||||
if (element is Image && ImageResizeHandlesCanvas?.Visibility == Visibility.Visible)
|
if (IsBitmapLikeCanvasElement(element) && ImageResizeHandlesCanvas?.Visibility == Visibility.Visible)
|
||||||
{
|
{
|
||||||
UpdateImageResizeHandlesPosition(GetElementActualBounds(element));
|
UpdateImageResizeHandlesPosition(GetElementActualBounds(element));
|
||||||
}
|
}
|
||||||
@@ -306,13 +307,13 @@ namespace Ink_Canvas
|
|||||||
ApplyWheelScaleTransform(element, e);
|
ApplyWheelScaleTransform(element, e);
|
||||||
|
|
||||||
// 如果是图片元素,更新工具栏位置
|
// 如果是图片元素,更新工具栏位置
|
||||||
if (element is Image && BorderImageSelectionControl?.Visibility == Visibility.Visible)
|
if (IsBitmapLikeCanvasElement(element) && BorderImageSelectionControl?.Visibility == Visibility.Visible)
|
||||||
{
|
{
|
||||||
UpdateImageSelectionToolbarPosition(element);
|
UpdateImageSelectionToolbarPosition(element);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 如果是图片元素,更新选择点位置
|
// 如果是图片元素,更新选择点位置
|
||||||
if (element is Image && ImageResizeHandlesCanvas?.Visibility == Visibility.Visible)
|
if (IsBitmapLikeCanvasElement(element) && ImageResizeHandlesCanvas?.Visibility == Visibility.Visible)
|
||||||
{
|
{
|
||||||
UpdateImageResizeHandlesPosition(GetElementActualBounds(element));
|
UpdateImageResizeHandlesPosition(GetElementActualBounds(element));
|
||||||
}
|
}
|
||||||
@@ -396,13 +397,13 @@ namespace Ink_Canvas
|
|||||||
ApplyTouchManipulationTransform(element, e);
|
ApplyTouchManipulationTransform(element, e);
|
||||||
|
|
||||||
// 如果是图片元素,更新工具栏位置
|
// 如果是图片元素,更新工具栏位置
|
||||||
if (element is Image && BorderImageSelectionControl?.Visibility == Visibility.Visible)
|
if (IsBitmapLikeCanvasElement(element) && BorderImageSelectionControl?.Visibility == Visibility.Visible)
|
||||||
{
|
{
|
||||||
UpdateImageSelectionToolbarPosition(element);
|
UpdateImageSelectionToolbarPosition(element);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 如果是图片元素,更新选择点位置
|
// 如果是图片元素,更新选择点位置
|
||||||
if (element is Image && ImageResizeHandlesCanvas?.Visibility == Visibility.Visible)
|
if (IsBitmapLikeCanvasElement(element) && ImageResizeHandlesCanvas?.Visibility == Visibility.Visible)
|
||||||
{
|
{
|
||||||
UpdateImageResizeHandlesPosition(GetElementActualBounds(element));
|
UpdateImageResizeHandlesPosition(GetElementActualBounds(element));
|
||||||
}
|
}
|
||||||
@@ -523,12 +524,15 @@ namespace Ink_Canvas
|
|||||||
currentSelectedElement = element;
|
currentSelectedElement = element;
|
||||||
|
|
||||||
// 根据元素类型显示不同的选择工具栏
|
// 根据元素类型显示不同的选择工具栏
|
||||||
if (element is Image)
|
if (IsBitmapLikeCanvasElement(element))
|
||||||
{
|
{
|
||||||
|
if (BorderPdfPageSidebar != null)
|
||||||
|
BorderPdfPageSidebar.Visibility = element is PdfEmbeddedView ? Visibility.Visible : Visibility.Collapsed;
|
||||||
|
|
||||||
// 显示图片选择工具栏并设置位置
|
// 显示图片选择工具栏并设置位置
|
||||||
if (BorderImageSelectionControl != null)
|
if (BorderImageSelectionControl != null)
|
||||||
{
|
{
|
||||||
// 计算工具栏位置
|
// 计算工具栏位置(内部会同步 PDF 右侧栏位置)
|
||||||
UpdateImageSelectionToolbarPosition(element);
|
UpdateImageSelectionToolbarPosition(element);
|
||||||
BorderImageSelectionControl.Visibility = Visibility.Visible;
|
BorderImageSelectionControl.Visibility = Visibility.Visible;
|
||||||
}
|
}
|
||||||
@@ -536,11 +540,25 @@ namespace Ink_Canvas
|
|||||||
// 显示图片缩放选择点
|
// 显示图片缩放选择点
|
||||||
ShowImageResizeHandles(element);
|
ShowImageResizeHandles(element);
|
||||||
|
|
||||||
|
if (element is PdfEmbeddedView pdfView)
|
||||||
|
{
|
||||||
|
pdfView.PageNavigationStateChanged -= SelectedPdf_PageNavigationStateChanged;
|
||||||
|
pdfView.PageNavigationStateChanged += SelectedPdf_PageNavigationStateChanged;
|
||||||
|
UpdatePdfSidebarFromSelectedPdf();
|
||||||
|
UpdatePdfPageSidebarPosition(pdfView);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
ResetPdfSidebarToIdle();
|
||||||
|
|
||||||
// 墨迹选择工具栏通过GridInkCanvasSelectionCover的可见性来控制
|
// 墨迹选择工具栏通过GridInkCanvasSelectionCover的可见性来控制
|
||||||
// 不需要直接设置BorderStrokeSelectionControl.Visibility
|
// 不需要直接设置BorderStrokeSelectionControl.Visibility
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
if (BorderPdfPageSidebar != null)
|
||||||
|
BorderPdfPageSidebar.Visibility = Visibility.Collapsed;
|
||||||
|
ResetPdfSidebarToIdle();
|
||||||
|
|
||||||
// 隐藏图片选择工具栏
|
// 隐藏图片选择工具栏
|
||||||
if (BorderImageSelectionControl != null)
|
if (BorderImageSelectionControl != null)
|
||||||
{
|
{
|
||||||
@@ -584,6 +602,15 @@ namespace Ink_Canvas
|
|||||||
{
|
{
|
||||||
// 去除选中效果
|
// 去除选中效果
|
||||||
|
|
||||||
|
if (element is PdfEmbeddedView pdfView)
|
||||||
|
{
|
||||||
|
pdfView.PageNavigationStateChanged -= SelectedPdf_PageNavigationStateChanged;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (BorderPdfPageSidebar != null)
|
||||||
|
BorderPdfPageSidebar.Visibility = Visibility.Collapsed;
|
||||||
|
ResetPdfSidebarToIdle();
|
||||||
|
|
||||||
// 隐藏图片选择工具栏
|
// 隐藏图片选择工具栏
|
||||||
if (BorderImageSelectionControl != null)
|
if (BorderImageSelectionControl != null)
|
||||||
{
|
{
|
||||||
@@ -914,15 +941,24 @@ namespace Ink_Canvas
|
|||||||
/// - 否则使用原始尺寸
|
/// - 否则使用原始尺寸
|
||||||
/// - 返回创建的Image对象
|
/// - 返回创建的Image对象
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
private async Task<Image> CreateAndCompressImageAsync(string filePath)
|
/// <summary>与图片选择工具栏、缩放控制点联动的画布位图类元素(普通图片或多页 PDF 嵌入)。</summary>
|
||||||
|
private static bool IsBitmapLikeCanvasElement(FrameworkElement fe)
|
||||||
{
|
{
|
||||||
|
return fe is Image || fe is PdfEmbeddedView;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<FrameworkElement> CreateAndCompressImageAsync(string filePath)
|
||||||
|
{
|
||||||
|
string fileExtension = Path.GetExtension(filePath);
|
||||||
|
if (string.Equals(fileExtension, ".pdf", StringComparison.OrdinalIgnoreCase))
|
||||||
|
return await CreateAndCompressImageFromPdfAsync(filePath);
|
||||||
|
|
||||||
string savePath = Path.Combine(Settings.Automation.AutoSavedStrokesLocation, "File Dependency");
|
string savePath = Path.Combine(Settings.Automation.AutoSavedStrokesLocation, "File Dependency");
|
||||||
if (!Directory.Exists(savePath))
|
if (!Directory.Exists(savePath))
|
||||||
{
|
{
|
||||||
Directory.CreateDirectory(savePath);
|
Directory.CreateDirectory(savePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
string fileExtension = Path.GetExtension(filePath);
|
|
||||||
string timestamp = "img_" + DateTime.Now.ToString("yyyyMMdd_HH_mm_ss_fff");
|
string timestamp = "img_" + DateTime.Now.ToString("yyyyMMdd_HH_mm_ss_fff");
|
||||||
string newFilePath = Path.Combine(savePath, timestamp + fileExtension);
|
string newFilePath = Path.Combine(savePath, timestamp + fileExtension);
|
||||||
|
|
||||||
@@ -965,6 +1001,43 @@ namespace Ink_Canvas
|
|||||||
return image;
|
return image;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 插入完整 PDF:嵌入控件内可翻页,右下角显示页码(类似希沃白板交互)。
|
||||||
|
/// </summary>
|
||||||
|
private async Task<PdfEmbeddedView> CreateAndCompressImageFromPdfAsync(string filePath)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string savePath = Path.Combine(Settings.Automation.AutoSavedStrokesLocation, "File Dependency");
|
||||||
|
if (!Directory.Exists(savePath))
|
||||||
|
Directory.CreateDirectory(savePath);
|
||||||
|
|
||||||
|
string timestamp = "img_" + DateTime.Now.ToString("yyyyMMdd_HH_mm_ss_fff");
|
||||||
|
string newFilePath = Path.Combine(savePath, timestamp + ".pdf");
|
||||||
|
await Task.Run(() => File.Copy(filePath, newFilePath, true));
|
||||||
|
|
||||||
|
uint pageCount = await PdfWinRtHelper.GetPageCountAsync(newFilePath);
|
||||||
|
if (pageCount == 0)
|
||||||
|
{
|
||||||
|
ShowNotification("无法打开 PDF(可能已加密、损坏或不支持)。");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool compress = isLoaded && Settings.Canvas.IsCompressPicturesUploaded;
|
||||||
|
var view = new PdfEmbeddedView();
|
||||||
|
await view.InitializeAsync(newFilePath, pageCount, compress);
|
||||||
|
view.Tag = filePath;
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
LogHelper.WriteLogToFile($"插入 PDF 失败: {ex.Message}", LogHelper.LogType.Error);
|
||||||
|
ShowNotification($"插入 PDF 失败: {ex.Message}");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Media
|
#region Media
|
||||||
@@ -1453,6 +1526,9 @@ namespace Ink_Canvas
|
|||||||
|
|
||||||
// 设置工具栏位置
|
// 设置工具栏位置
|
||||||
BorderImageSelectionControl.Margin = new Thickness(toolbarLeft, toolbarTop, 0, 0);
|
BorderImageSelectionControl.Margin = new Thickness(toolbarLeft, toolbarTop, 0, 0);
|
||||||
|
|
||||||
|
if (element is PdfEmbeddedView && BorderPdfPageSidebar?.Visibility == Visibility.Visible)
|
||||||
|
UpdatePdfPageSidebarPosition(element);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -1460,6 +1536,54 @@ namespace Ink_Canvas
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private const double PdfPageSidebarGap = 10;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 将 PDF 专用页码栏贴在当前所选 PDF 的右侧(画布坐标,与底部选中栏一致)。
|
||||||
|
/// </summary>
|
||||||
|
private void UpdatePdfPageSidebarPosition(FrameworkElement element)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (BorderPdfPageSidebar == null || inkCanvas == null || !(element is PdfEmbeddedView))
|
||||||
|
return;
|
||||||
|
|
||||||
|
Rect b = GetElementActualBounds(element);
|
||||||
|
|
||||||
|
BorderPdfPageSidebar.Measure(new Size(BorderPdfPageSidebar.Width, double.PositiveInfinity));
|
||||||
|
double sidebarW = BorderPdfPageSidebar.DesiredSize.Width;
|
||||||
|
double sidebarH = BorderPdfPageSidebar.DesiredSize.Height;
|
||||||
|
if (sidebarW <= 0)
|
||||||
|
sidebarW = BorderPdfPageSidebar.Width;
|
||||||
|
if (sidebarH <= 0)
|
||||||
|
sidebarH = BorderPdfPageSidebar.ActualHeight;
|
||||||
|
if (sidebarH <= 0)
|
||||||
|
sidebarH = 220;
|
||||||
|
|
||||||
|
double left = b.Right + PdfPageSidebarGap;
|
||||||
|
double top = b.Top + (b.Height * 0.5) - (sidebarH * 0.5);
|
||||||
|
|
||||||
|
double maxLeft = Math.Max(0, inkCanvas.ActualWidth - sidebarW);
|
||||||
|
double maxTop = Math.Max(0, inkCanvas.ActualHeight - sidebarH);
|
||||||
|
|
||||||
|
if (left > maxLeft)
|
||||||
|
{
|
||||||
|
double leftAlt = b.Left - PdfPageSidebarGap - sidebarW;
|
||||||
|
if (leftAlt >= 0)
|
||||||
|
left = leftAlt;
|
||||||
|
}
|
||||||
|
|
||||||
|
left = Math.Max(0, Math.Min(left, maxLeft));
|
||||||
|
top = Math.Max(0, Math.Min(top, maxTop));
|
||||||
|
|
||||||
|
BorderPdfPageSidebar.Margin = new Thickness(left, top, 0, 0);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
LogHelper.WriteLogToFile($"更新 PDF 右侧页码栏位置失败: {ex.Message}", LogHelper.LogType.Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 获取元素的实际边界(考虑变换)
|
/// 获取元素的实际边界(考虑变换)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -1644,7 +1768,7 @@ namespace Ink_Canvas
|
|||||||
ApplyRotateTransform(currentSelectedElement, -45);
|
ApplyRotateTransform(currentSelectedElement, -45);
|
||||||
|
|
||||||
// 更新工具栏位置
|
// 更新工具栏位置
|
||||||
if (currentSelectedElement is Image && BorderImageSelectionControl?.Visibility == Visibility.Visible)
|
if (IsBitmapLikeCanvasElement(currentSelectedElement) && BorderImageSelectionControl?.Visibility == Visibility.Visible)
|
||||||
{
|
{
|
||||||
UpdateImageSelectionToolbarPosition(currentSelectedElement);
|
UpdateImageSelectionToolbarPosition(currentSelectedElement);
|
||||||
}
|
}
|
||||||
@@ -1678,7 +1802,7 @@ namespace Ink_Canvas
|
|||||||
ApplyRotateTransform(currentSelectedElement, 45);
|
ApplyRotateTransform(currentSelectedElement, 45);
|
||||||
|
|
||||||
// 更新工具栏位置
|
// 更新工具栏位置
|
||||||
if (currentSelectedElement is Image && BorderImageSelectionControl?.Visibility == Visibility.Visible)
|
if (IsBitmapLikeCanvasElement(currentSelectedElement) && BorderImageSelectionControl?.Visibility == Visibility.Visible)
|
||||||
{
|
{
|
||||||
UpdateImageSelectionToolbarPosition(currentSelectedElement);
|
UpdateImageSelectionToolbarPosition(currentSelectedElement);
|
||||||
}
|
}
|
||||||
@@ -1714,7 +1838,7 @@ namespace Ink_Canvas
|
|||||||
ApplyScaleTransform(currentSelectedElement, 0.9, elementCenter);
|
ApplyScaleTransform(currentSelectedElement, 0.9, elementCenter);
|
||||||
|
|
||||||
// 更新工具栏位置
|
// 更新工具栏位置
|
||||||
if (currentSelectedElement is Image && BorderImageSelectionControl?.Visibility == Visibility.Visible)
|
if (IsBitmapLikeCanvasElement(currentSelectedElement) && BorderImageSelectionControl?.Visibility == Visibility.Visible)
|
||||||
{
|
{
|
||||||
UpdateImageSelectionToolbarPosition(currentSelectedElement);
|
UpdateImageSelectionToolbarPosition(currentSelectedElement);
|
||||||
}
|
}
|
||||||
@@ -1750,7 +1874,7 @@ namespace Ink_Canvas
|
|||||||
ApplyScaleTransform(currentSelectedElement, 1.1, elementCenter);
|
ApplyScaleTransform(currentSelectedElement, 1.1, elementCenter);
|
||||||
|
|
||||||
// 更新工具栏位置
|
// 更新工具栏位置
|
||||||
if (currentSelectedElement is Image && BorderImageSelectionControl?.Visibility == Visibility.Visible)
|
if (IsBitmapLikeCanvasElement(currentSelectedElement) && BorderImageSelectionControl?.Visibility == Visibility.Visible)
|
||||||
{
|
{
|
||||||
UpdateImageSelectionToolbarPosition(currentSelectedElement);
|
UpdateImageSelectionToolbarPosition(currentSelectedElement);
|
||||||
}
|
}
|
||||||
@@ -1764,19 +1888,96 @@ namespace Ink_Canvas
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void ResetPdfSidebarToIdle()
|
||||||
|
{
|
||||||
|
if (TextBlockPdfSidebarPageLabel != null)
|
||||||
|
{
|
||||||
|
TextBlockPdfSidebarPageLabel.Text = "— / —";
|
||||||
|
TextBlockPdfSidebarPageLabel.Opacity = 0.55;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (BorderPdfSidebarPagePrev != null)
|
||||||
|
{
|
||||||
|
BorderPdfSidebarPagePrev.Opacity = 0.35;
|
||||||
|
BorderPdfSidebarPagePrev.IsHitTestVisible = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (BorderPdfSidebarPageNext != null)
|
||||||
|
{
|
||||||
|
BorderPdfSidebarPageNext.Opacity = 0.35;
|
||||||
|
BorderPdfSidebarPageNext.IsHitTestVisible = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdatePdfSidebarFromSelectedPdf()
|
||||||
|
{
|
||||||
|
if (currentSelectedElement is PdfEmbeddedView pdf)
|
||||||
|
{
|
||||||
|
if (TextBlockPdfSidebarPageLabel != null)
|
||||||
|
{
|
||||||
|
TextBlockPdfSidebarPageLabel.Text = pdf.PageLabelText;
|
||||||
|
TextBlockPdfSidebarPageLabel.Opacity = 1.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool prevOk = pdf.CanGoPrevious;
|
||||||
|
bool nextOk = pdf.CanGoNext;
|
||||||
|
if (BorderPdfSidebarPagePrev != null)
|
||||||
|
{
|
||||||
|
BorderPdfSidebarPagePrev.Opacity = prevOk ? 1.0 : 0.35;
|
||||||
|
BorderPdfSidebarPagePrev.IsHitTestVisible = prevOk;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (BorderPdfSidebarPageNext != null)
|
||||||
|
{
|
||||||
|
BorderPdfSidebarPageNext.Opacity = nextOk ? 1.0 : 0.35;
|
||||||
|
BorderPdfSidebarPageNext.IsHitTestVisible = nextOk;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SelectedPdf_PageNavigationStateChanged(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
Dispatcher.BeginInvoke(new Action(() =>
|
||||||
|
{
|
||||||
|
UpdatePdfSidebarFromSelectedPdf();
|
||||||
|
if (currentSelectedElement != null && IsBitmapLikeCanvasElement(currentSelectedElement))
|
||||||
|
{
|
||||||
|
UpdateImageSelectionToolbarPosition(currentSelectedElement);
|
||||||
|
if (ImageResizeHandlesCanvas?.Visibility == Visibility.Visible)
|
||||||
|
UpdateImageResizeHandlesPosition(GetElementActualBounds(currentSelectedElement));
|
||||||
|
}
|
||||||
|
}), DispatcherPriority.Background);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async void BorderPdfSidebarPagePrev_MouseUp(object sender, MouseButtonEventArgs e)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (currentSelectedElement is PdfEmbeddedView pdf && pdf.CanGoPrevious)
|
||||||
|
await pdf.GoToPreviousPageAsync();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
LogHelper.WriteLogToFile($"PDF 上一页失败: {ex.Message}", LogHelper.LogType.Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async void BorderPdfSidebarPageNext_MouseUp(object sender, MouseButtonEventArgs e)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (currentSelectedElement is PdfEmbeddedView pdf && pdf.CanGoNext)
|
||||||
|
await pdf.GoToNextPageAsync();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
LogHelper.WriteLogToFile($"PDF 下一页失败: {ex.Message}", LogHelper.LogType.Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 处理图片删除功能
|
/// 处理图片删除功能
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="sender">事件发送者</param>
|
|
||||||
/// <param name="e">事件参数</param>
|
|
||||||
/// <remarks>
|
|
||||||
/// - 检查当前是否有选中元素
|
|
||||||
/// - 保存删除前的编辑模式
|
|
||||||
/// - 记录删除历史
|
|
||||||
/// - 从画布中移除
|
|
||||||
/// - 清除选中状态
|
|
||||||
/// - 包含异常处理
|
|
||||||
/// </remarks>
|
|
||||||
private void BorderImageDelete_MouseUp(object sender, MouseButtonEventArgs e)
|
private void BorderImageDelete_MouseUp(object sender, MouseButtonEventArgs e)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@@ -1789,11 +1990,12 @@ namespace Ink_Canvas
|
|||||||
// 记录删除历史
|
// 记录删除历史
|
||||||
timeMachine.CommitElementRemoveHistory(currentSelectedElement);
|
timeMachine.CommitElementRemoveHistory(currentSelectedElement);
|
||||||
|
|
||||||
|
var toRemove = currentSelectedElement;
|
||||||
// 从画布中移除
|
// 从画布中移除
|
||||||
inkCanvas.Children.Remove(currentSelectedElement);
|
inkCanvas.Children.Remove(toRemove);
|
||||||
|
|
||||||
// 清除选中状态
|
// 清除选中状态
|
||||||
UnselectElement(currentSelectedElement);
|
UnselectElement(toRemove);
|
||||||
currentSelectedElement = null;
|
currentSelectedElement = null;
|
||||||
|
|
||||||
// 恢复到删除前的编辑模式
|
// 恢复到删除前的编辑模式
|
||||||
@@ -2029,7 +2231,7 @@ namespace Ink_Canvas
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (currentSelectedElement is Image image && sender is Ellipse ellipse)
|
if (IsBitmapLikeCanvasElement(currentSelectedElement) && sender is Ellipse ellipse)
|
||||||
{
|
{
|
||||||
isResizingImage = true;
|
isResizingImage = true;
|
||||||
imageResizeStartPoint = e.GetPosition(inkCanvas);
|
imageResizeStartPoint = e.GetPosition(inkCanvas);
|
||||||
@@ -2072,10 +2274,10 @@ namespace Ink_Canvas
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (isResizingImage && currentSelectedElement is Image image && sender is Ellipse ellipse)
|
if (isResizingImage && IsBitmapLikeCanvasElement(currentSelectedElement) && sender is Ellipse ellipse)
|
||||||
{
|
{
|
||||||
var currentPoint = e.GetPosition(inkCanvas);
|
var currentPoint = e.GetPosition(inkCanvas);
|
||||||
ResizeImageByHandle(image, imageResizeStartPoint, currentPoint, activeResizeHandle);
|
ResizeImageByHandle(currentSelectedElement, imageResizeStartPoint, currentPoint, activeResizeHandle);
|
||||||
imageResizeStartPoint = currentPoint;
|
imageResizeStartPoint = currentPoint;
|
||||||
e.Handled = true;
|
e.Handled = true;
|
||||||
}
|
}
|
||||||
@@ -2087,11 +2289,11 @@ namespace Ink_Canvas
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 根据控制点缩放图片
|
// 根据控制点缩放图片
|
||||||
private void ResizeImageByHandle(Image image, Point startPoint, Point currentPoint, string handleName)
|
private void ResizeImageByHandle(FrameworkElement element, Point startPoint, Point currentPoint, string handleName)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (image.RenderTransform is TransformGroup transformGroup)
|
if (element.RenderTransform is TransformGroup transformGroup)
|
||||||
{
|
{
|
||||||
var scaleTransform = transformGroup.Children.OfType<ScaleTransform>().FirstOrDefault();
|
var scaleTransform = transformGroup.Children.OfType<ScaleTransform>().FirstOrDefault();
|
||||||
var translateTransform = transformGroup.Children.OfType<TranslateTransform>().FirstOrDefault();
|
var translateTransform = transformGroup.Children.OfType<TranslateTransform>().FirstOrDefault();
|
||||||
@@ -2099,7 +2301,7 @@ namespace Ink_Canvas
|
|||||||
if (scaleTransform == null || translateTransform == null) return;
|
if (scaleTransform == null || translateTransform == null) return;
|
||||||
|
|
||||||
// 获取图片的当前边界
|
// 获取图片的当前边界
|
||||||
Rect currentBounds = GetElementActualBounds(image);
|
Rect currentBounds = GetElementActualBounds(element);
|
||||||
double deltaX = currentPoint.X - startPoint.X;
|
double deltaX = currentPoint.X - startPoint.X;
|
||||||
double deltaY = currentPoint.Y - startPoint.Y;
|
double deltaY = currentPoint.Y - startPoint.Y;
|
||||||
|
|
||||||
@@ -2160,7 +2362,10 @@ namespace Ink_Canvas
|
|||||||
translateTransform.Y += translateY;
|
translateTransform.Y += translateY;
|
||||||
|
|
||||||
// 更新选择点位置
|
// 更新选择点位置
|
||||||
UpdateImageResizeHandlesPosition(GetElementActualBounds(image));
|
UpdateImageResizeHandlesPosition(GetElementActualBounds(element));
|
||||||
|
|
||||||
|
if (BorderImageSelectionControl?.Visibility == Visibility.Visible)
|
||||||
|
UpdateImageSelectionToolbarPosition(element);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
using Ink_Canvas.Controls;
|
||||||
using Ink_Canvas.Helpers;
|
using Ink_Canvas.Helpers;
|
||||||
using iNKORE.UI.WPF.Modern;
|
using iNKORE.UI.WPF.Modern;
|
||||||
using System;
|
using System;
|
||||||
@@ -3774,32 +3775,29 @@ namespace Ink_Canvas
|
|||||||
// Open file dialog to select image
|
// Open file dialog to select image
|
||||||
var dialog = new OpenFileDialog
|
var dialog = new OpenFileDialog
|
||||||
{
|
{
|
||||||
Filter = "图片文件|*.jpg;*.jpeg;*.png;*.bmp;*.gif"
|
Filter = "图片与 PDF|*.jpg;*.jpeg;*.png;*.bmp;*.gif;*.pdf|图片文件|*.jpg;*.jpeg;*.png;*.bmp;*.gif|PDF|*.pdf"
|
||||||
};
|
};
|
||||||
if (dialog.ShowDialog() == true)
|
if (dialog.ShowDialog() == true)
|
||||||
{
|
{
|
||||||
string filePath = dialog.FileName;
|
string filePath = dialog.FileName;
|
||||||
Image image = await CreateAndCompressImageAsync(filePath);
|
FrameworkElement element = await CreateAndCompressImageAsync(filePath);
|
||||||
if (image != null)
|
if (element != null)
|
||||||
{
|
{
|
||||||
string timestamp = "img_" + DateTime.Now.ToString("yyyyMMdd_HH_mm_ss_fff");
|
string timestamp = "img_" + DateTime.Now.ToString("yyyyMMdd_HH_mm_ss_fff");
|
||||||
image.Name = timestamp;
|
element.Name = timestamp;
|
||||||
|
|
||||||
// 初始化TransformGroup
|
// 初始化TransformGroup
|
||||||
if (image is FrameworkElement element)
|
var transformGroup = new TransformGroup();
|
||||||
{
|
transformGroup.Children.Add(new ScaleTransform(1, 1));
|
||||||
var transformGroup = new TransformGroup();
|
transformGroup.Children.Add(new TranslateTransform(0, 0));
|
||||||
transformGroup.Children.Add(new ScaleTransform(1, 1));
|
transformGroup.Children.Add(new RotateTransform(0));
|
||||||
transformGroup.Children.Add(new TranslateTransform(0, 0));
|
element.RenderTransform = transformGroup;
|
||||||
transformGroup.Children.Add(new RotateTransform(0));
|
|
||||||
element.RenderTransform = transformGroup;
|
|
||||||
}
|
|
||||||
|
|
||||||
CenterAndScaleElement(image);
|
CenterAndScaleElement(element);
|
||||||
|
|
||||||
// 设置图片属性,避免被InkCanvas选择系统处理
|
// 设置图片属性,避免被InkCanvas选择系统处理
|
||||||
image.IsHitTestVisible = true;
|
element.IsHitTestVisible = true;
|
||||||
image.Focusable = false;
|
element.Focusable = false;
|
||||||
|
|
||||||
// 初始化InkCanvas选择设置
|
// 初始化InkCanvas选择设置
|
||||||
if (inkCanvas != null)
|
if (inkCanvas != null)
|
||||||
@@ -3810,29 +3808,25 @@ namespace Ink_Canvas
|
|||||||
inkCanvas.EditingMode = InkCanvasEditingMode.None;
|
inkCanvas.EditingMode = InkCanvasEditingMode.None;
|
||||||
}
|
}
|
||||||
|
|
||||||
inkCanvas.Children.Add(image);
|
inkCanvas.Children.Add(element);
|
||||||
|
|
||||||
// 绑定事件处理器
|
// 绑定事件处理器
|
||||||
if (image is FrameworkElement elementForEvents)
|
element.MouseLeftButtonDown += Element_MouseLeftButtonDown;
|
||||||
{
|
element.MouseLeftButtonUp += Element_MouseLeftButtonUp;
|
||||||
// 鼠标事件
|
element.MouseMove += Element_MouseMove;
|
||||||
elementForEvents.MouseLeftButtonDown += Element_MouseLeftButtonDown;
|
element.MouseWheel += Element_MouseWheel;
|
||||||
elementForEvents.MouseLeftButtonUp += Element_MouseLeftButtonUp;
|
|
||||||
elementForEvents.MouseMove += Element_MouseMove;
|
|
||||||
elementForEvents.MouseWheel += Element_MouseWheel;
|
|
||||||
|
|
||||||
// 触摸事件
|
// 触摸事件
|
||||||
elementForEvents.TouchDown += Element_TouchDown;
|
element.TouchDown += Element_TouchDown;
|
||||||
elementForEvents.TouchUp += Element_TouchUp;
|
element.TouchUp += Element_TouchUp;
|
||||||
elementForEvents.IsManipulationEnabled = true;
|
element.IsManipulationEnabled = true;
|
||||||
elementForEvents.ManipulationDelta += Element_ManipulationDelta;
|
element.ManipulationDelta += Element_ManipulationDelta;
|
||||||
elementForEvents.ManipulationCompleted += Element_ManipulationCompleted;
|
element.ManipulationCompleted += Element_ManipulationCompleted;
|
||||||
|
|
||||||
// 设置光标
|
// 设置光标
|
||||||
elementForEvents.Cursor = Cursors.Hand;
|
element.Cursor = Cursors.Hand;
|
||||||
}
|
|
||||||
|
|
||||||
timeMachine.CommitElementInsertHistory(image);
|
timeMachine.CommitElementInsertHistory(element);
|
||||||
|
|
||||||
// 插入图片后切换到选择模式并刷新浮动栏高光显示
|
// 插入图片后切换到选择模式并刷新浮动栏高光显示
|
||||||
SetCurrentToolMode(InkCanvasEditingMode.Select);
|
SetCurrentToolMode(InkCanvasEditingMode.Select);
|
||||||
@@ -3847,32 +3841,29 @@ namespace Ink_Canvas
|
|||||||
{
|
{
|
||||||
var dialog = new OpenFileDialog
|
var dialog = new OpenFileDialog
|
||||||
{
|
{
|
||||||
Filter = "图片文件|*.jpg;*.jpeg;*.png;*.bmp;*.gif"
|
Filter = "图片与 PDF|*.jpg;*.jpeg;*.png;*.bmp;*.gif;*.pdf|图片文件|*.jpg;*.jpeg;*.png;*.bmp;*.gif|PDF|*.pdf"
|
||||||
};
|
};
|
||||||
if (dialog.ShowDialog() == true)
|
if (dialog.ShowDialog() == true)
|
||||||
{
|
{
|
||||||
string filePath = dialog.FileName;
|
string filePath = dialog.FileName;
|
||||||
Image image = await CreateAndCompressImageAsync(filePath);
|
FrameworkElement element = await CreateAndCompressImageAsync(filePath);
|
||||||
if (image != null)
|
if (element != null)
|
||||||
{
|
{
|
||||||
string timestamp = "img_" + DateTime.Now.ToString("yyyyMMdd_HH_mm_ss_fff");
|
string timestamp = "img_" + DateTime.Now.ToString("yyyyMMdd_HH_mm_ss_fff");
|
||||||
image.Name = timestamp;
|
element.Name = timestamp;
|
||||||
|
|
||||||
// 初始化TransformGroup
|
// 初始化TransformGroup
|
||||||
if (image is FrameworkElement element)
|
var transformGroup = new TransformGroup();
|
||||||
{
|
transformGroup.Children.Add(new ScaleTransform(1, 1));
|
||||||
var transformGroup = new TransformGroup();
|
transformGroup.Children.Add(new TranslateTransform(0, 0));
|
||||||
transformGroup.Children.Add(new ScaleTransform(1, 1));
|
transformGroup.Children.Add(new RotateTransform(0));
|
||||||
transformGroup.Children.Add(new TranslateTransform(0, 0));
|
element.RenderTransform = transformGroup;
|
||||||
transformGroup.Children.Add(new RotateTransform(0));
|
|
||||||
element.RenderTransform = transformGroup;
|
|
||||||
}
|
|
||||||
|
|
||||||
CenterAndScaleElement(image);
|
CenterAndScaleElement(element);
|
||||||
|
|
||||||
// 设置图片属性,避免被InkCanvas选择系统处理
|
// 设置图片属性,避免被InkCanvas选择系统处理
|
||||||
image.IsHitTestVisible = true;
|
element.IsHitTestVisible = true;
|
||||||
image.Focusable = false;
|
element.Focusable = false;
|
||||||
|
|
||||||
// 初始化InkCanvas选择设置
|
// 初始化InkCanvas选择设置
|
||||||
if (inkCanvas != null)
|
if (inkCanvas != null)
|
||||||
@@ -3883,29 +3874,25 @@ namespace Ink_Canvas
|
|||||||
inkCanvas.EditingMode = InkCanvasEditingMode.None;
|
inkCanvas.EditingMode = InkCanvasEditingMode.None;
|
||||||
}
|
}
|
||||||
|
|
||||||
inkCanvas.Children.Add(image);
|
inkCanvas.Children.Add(element);
|
||||||
|
|
||||||
// 绑定事件处理器
|
// 绑定事件处理器
|
||||||
if (image is FrameworkElement elementForEvents)
|
element.MouseLeftButtonDown += Element_MouseLeftButtonDown;
|
||||||
{
|
element.MouseLeftButtonUp += Element_MouseLeftButtonUp;
|
||||||
// 鼠标事件
|
element.MouseMove += Element_MouseMove;
|
||||||
elementForEvents.MouseLeftButtonDown += Element_MouseLeftButtonDown;
|
element.MouseWheel += Element_MouseWheel;
|
||||||
elementForEvents.MouseLeftButtonUp += Element_MouseLeftButtonUp;
|
|
||||||
elementForEvents.MouseMove += Element_MouseMove;
|
|
||||||
elementForEvents.MouseWheel += Element_MouseWheel;
|
|
||||||
|
|
||||||
// 触摸事件
|
// 触摸事件
|
||||||
elementForEvents.TouchDown += Element_TouchDown;
|
element.TouchDown += Element_TouchDown;
|
||||||
elementForEvents.TouchUp += Element_TouchUp;
|
element.TouchUp += Element_TouchUp;
|
||||||
elementForEvents.IsManipulationEnabled = true;
|
element.IsManipulationEnabled = true;
|
||||||
elementForEvents.ManipulationDelta += Element_ManipulationDelta;
|
element.ManipulationDelta += Element_ManipulationDelta;
|
||||||
elementForEvents.ManipulationCompleted += Element_ManipulationCompleted;
|
element.ManipulationCompleted += Element_ManipulationCompleted;
|
||||||
|
|
||||||
// 设置光标
|
// 设置光标
|
||||||
elementForEvents.Cursor = Cursors.Hand;
|
element.Cursor = Cursors.Hand;
|
||||||
}
|
|
||||||
|
|
||||||
timeMachine.CommitElementInsertHistory(image);
|
timeMachine.CommitElementInsertHistory(element);
|
||||||
|
|
||||||
// 插入图片后切换到选择模式并刷新浮动栏高光显示
|
// 插入图片后切换到选择模式并刷新浮动栏高光显示
|
||||||
SetCurrentToolMode(InkCanvasEditingMode.Select);
|
SetCurrentToolMode(InkCanvasEditingMode.Select);
|
||||||
@@ -3920,32 +3907,29 @@ namespace Ink_Canvas
|
|||||||
{
|
{
|
||||||
var dialog = new OpenFileDialog
|
var dialog = new OpenFileDialog
|
||||||
{
|
{
|
||||||
Filter = "图片文件|*.jpg;*.jpeg;*.png;*.bmp;*.gif"
|
Filter = "图片与 PDF|*.jpg;*.jpeg;*.png;*.bmp;*.gif;*.pdf|图片文件|*.jpg;*.jpeg;*.png;*.bmp;*.gif|PDF|*.pdf"
|
||||||
};
|
};
|
||||||
if (dialog.ShowDialog() == true)
|
if (dialog.ShowDialog() == true)
|
||||||
{
|
{
|
||||||
string filePath = dialog.FileName;
|
string filePath = dialog.FileName;
|
||||||
Image image = await CreateAndCompressImageAsync(filePath); // 补充image定义
|
FrameworkElement element = await CreateAndCompressImageAsync(filePath);
|
||||||
if (image != null)
|
if (element != null)
|
||||||
{
|
{
|
||||||
string timestamp = "img_" + DateTime.Now.ToString("yyyyMMdd_HH_mm_ss_fff");
|
string timestamp = "img_" + DateTime.Now.ToString("yyyyMMdd_HH_mm_ss_fff");
|
||||||
image.Name = timestamp;
|
element.Name = timestamp;
|
||||||
|
|
||||||
// 初始化TransformGroup
|
// 初始化TransformGroup
|
||||||
if (image is FrameworkElement element)
|
var transformGroup = new TransformGroup();
|
||||||
{
|
transformGroup.Children.Add(new ScaleTransform(1, 1));
|
||||||
var transformGroup = new TransformGroup();
|
transformGroup.Children.Add(new TranslateTransform(0, 0));
|
||||||
transformGroup.Children.Add(new ScaleTransform(1, 1));
|
transformGroup.Children.Add(new RotateTransform(0));
|
||||||
transformGroup.Children.Add(new TranslateTransform(0, 0));
|
element.RenderTransform = transformGroup;
|
||||||
transformGroup.Children.Add(new RotateTransform(0));
|
|
||||||
element.RenderTransform = transformGroup;
|
|
||||||
}
|
|
||||||
|
|
||||||
CenterAndScaleElement(image);
|
CenterAndScaleElement(element);
|
||||||
|
|
||||||
// 设置图片属性,避免被InkCanvas选择系统处理
|
// 设置图片属性,避免被InkCanvas选择系统处理
|
||||||
image.IsHitTestVisible = true;
|
element.IsHitTestVisible = true;
|
||||||
image.Focusable = false;
|
element.Focusable = false;
|
||||||
|
|
||||||
// 初始化InkCanvas选择设置
|
// 初始化InkCanvas选择设置
|
||||||
if (inkCanvas != null)
|
if (inkCanvas != null)
|
||||||
@@ -3956,29 +3940,25 @@ namespace Ink_Canvas
|
|||||||
inkCanvas.EditingMode = InkCanvasEditingMode.None;
|
inkCanvas.EditingMode = InkCanvasEditingMode.None;
|
||||||
}
|
}
|
||||||
|
|
||||||
inkCanvas.Children.Add(image);
|
inkCanvas.Children.Add(element);
|
||||||
|
|
||||||
// 绑定事件处理器
|
// 绑定事件处理器
|
||||||
if (image is FrameworkElement elementForEvents)
|
element.MouseLeftButtonDown += Element_MouseLeftButtonDown;
|
||||||
{
|
element.MouseLeftButtonUp += Element_MouseLeftButtonUp;
|
||||||
// 鼠标事件
|
element.MouseMove += Element_MouseMove;
|
||||||
elementForEvents.MouseLeftButtonDown += Element_MouseLeftButtonDown;
|
element.MouseWheel += Element_MouseWheel;
|
||||||
elementForEvents.MouseLeftButtonUp += Element_MouseLeftButtonUp;
|
|
||||||
elementForEvents.MouseMove += Element_MouseMove;
|
|
||||||
elementForEvents.MouseWheel += Element_MouseWheel;
|
|
||||||
|
|
||||||
// 触摸事件
|
// 触摸事件
|
||||||
elementForEvents.TouchDown += Element_TouchDown;
|
element.TouchDown += Element_TouchDown;
|
||||||
elementForEvents.TouchUp += Element_TouchUp;
|
element.TouchUp += Element_TouchUp;
|
||||||
elementForEvents.IsManipulationEnabled = true;
|
element.IsManipulationEnabled = true;
|
||||||
elementForEvents.ManipulationDelta += Element_ManipulationDelta;
|
element.ManipulationDelta += Element_ManipulationDelta;
|
||||||
elementForEvents.ManipulationCompleted += Element_ManipulationCompleted;
|
element.ManipulationCompleted += Element_ManipulationCompleted;
|
||||||
|
|
||||||
// 设置光标
|
// 设置光标
|
||||||
elementForEvents.Cursor = Cursors.Hand;
|
element.Cursor = Cursors.Hand;
|
||||||
}
|
|
||||||
|
|
||||||
timeMachine.CommitElementInsertHistory(image);
|
timeMachine.CommitElementInsertHistory(element);
|
||||||
|
|
||||||
// 插入图片后切换到选择模式并刷新浮动栏高光显示
|
// 插入图片后切换到选择模式并刷新浮动栏高光显示
|
||||||
SetCurrentToolMode(InkCanvasEditingMode.Select);
|
SetCurrentToolMode(InkCanvasEditingMode.Select);
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
using Ink_Canvas.Controls;
|
||||||
using Ink_Canvas.Helpers;
|
using Ink_Canvas.Helpers;
|
||||||
using iNKORE.UI.WPF.Controls;
|
using iNKORE.UI.WPF.Controls;
|
||||||
using System;
|
using System;
|
||||||
@@ -610,7 +611,7 @@ namespace Ink_Canvas
|
|||||||
|
|
||||||
// 检查是否有图片元素被选中(通过InkCanvas的选中元素)
|
// 检查是否有图片元素被选中(通过InkCanvas的选中元素)
|
||||||
var selectedElements = inkCanvas.GetSelectedElements();
|
var selectedElements = inkCanvas.GetSelectedElements();
|
||||||
bool hasImageElement = selectedElements.Any(element => element is Image);
|
bool hasImageElement = selectedElements.Any(element => element is Image || element is PdfEmbeddedView);
|
||||||
|
|
||||||
// 如果有图片元素被选中,不显示选择框
|
// 如果有图片元素被选中,不显示选择框
|
||||||
if (hasImageElement)
|
if (hasImageElement)
|
||||||
@@ -621,7 +622,7 @@ namespace Ink_Canvas
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 检查是否有图片元素被选中(通过currentSelectedElement)
|
// 检查是否有图片元素被选中(通过currentSelectedElement)
|
||||||
if (currentSelectedElement != null && currentSelectedElement is Image)
|
if (currentSelectedElement != null && (currentSelectedElement is Image || currentSelectedElement is PdfEmbeddedView))
|
||||||
{
|
{
|
||||||
GridInkCanvasSelectionCover.Visibility = Visibility.Collapsed;
|
GridInkCanvasSelectionCover.Visibility = Visibility.Collapsed;
|
||||||
HideSelectionDisplay();
|
HideSelectionDisplay();
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
using Ink_Canvas.Controls;
|
||||||
using Ink_Canvas.Helpers;
|
using Ink_Canvas.Helpers;
|
||||||
using Microsoft.Win32;
|
using Microsoft.Win32;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
@@ -101,7 +102,7 @@ namespace Ink_Canvas.Windows
|
|||||||
private double _collapsedOffset = 200; // 折叠时的偏移量(隐藏内容区域)
|
private double _collapsedOffset = 200; // 折叠时的偏移量(隐藏内容区域)
|
||||||
private MainWindow _mainWindow;
|
private MainWindow _mainWindow;
|
||||||
|
|
||||||
private Dictionary<System.Windows.Controls.Image, int> _pptImages = new Dictionary<System.Windows.Controls.Image, int>();
|
private Dictionary<FrameworkElement, int> _pptImages = new Dictionary<FrameworkElement, int>();
|
||||||
|
|
||||||
private Dictionary<int, List<string>> _pptImagePaths = new Dictionary<int, List<string>>();
|
private Dictionary<int, List<string>> _pptImagePaths = new Dictionary<int, List<string>>();
|
||||||
|
|
||||||
@@ -183,9 +184,9 @@ namespace Ink_Canvas.Windows
|
|||||||
{
|
{
|
||||||
foreach (var item in e.OldItems)
|
foreach (var item in e.OldItems)
|
||||||
{
|
{
|
||||||
if (item is System.Windows.Controls.Image image)
|
if (item is FrameworkElement fe && _pptImages.ContainsKey(fe))
|
||||||
{
|
{
|
||||||
RemoveImageFromPPT(image);
|
RemoveImageFromPPT(fe);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -196,20 +197,20 @@ namespace Ink_Canvas.Windows
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RemoveImageFromPPT(System.Windows.Controls.Image image)
|
private void RemoveImageFromPPT(FrameworkElement element)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (image == null) return;
|
if (element == null) return;
|
||||||
|
|
||||||
if (_pptImages.ContainsKey(image))
|
if (_pptImages.ContainsKey(element))
|
||||||
{
|
{
|
||||||
int slideNumber = _pptImages[image];
|
int slideNumber = _pptImages[element];
|
||||||
_pptImages.Remove(image);
|
_pptImages.Remove(element);
|
||||||
|
|
||||||
if (_pptImagePaths.ContainsKey(slideNumber))
|
if (_pptImagePaths.ContainsKey(slideNumber))
|
||||||
{
|
{
|
||||||
string imagePath = image.Tag as string;
|
string imagePath = element.Tag as string;
|
||||||
if (!string.IsNullOrEmpty(imagePath) && _pptImagePaths[slideNumber].Contains(imagePath))
|
if (!string.IsNullOrEmpty(imagePath) && _pptImagePaths[slideNumber].Contains(imagePath))
|
||||||
{
|
{
|
||||||
_pptImagePaths[slideNumber].Remove(imagePath);
|
_pptImagePaths[slideNumber].Remove(imagePath);
|
||||||
@@ -929,7 +930,7 @@ namespace Ink_Canvas.Windows
|
|||||||
{
|
{
|
||||||
var dialog = new OpenFileDialog
|
var dialog = new OpenFileDialog
|
||||||
{
|
{
|
||||||
Filter = "图片文件|*.jpg;*.jpeg;*.png;*.bmp;*.gif"
|
Filter = "图片与 PDF|*.jpg;*.jpeg;*.png;*.bmp;*.gif;*.pdf|图片文件|*.jpg;*.jpeg;*.png;*.bmp;*.gif|PDF|*.pdf"
|
||||||
};
|
};
|
||||||
|
|
||||||
if (dialog.ShowDialog() == true)
|
if (dialog.ShowDialog() == true)
|
||||||
@@ -941,14 +942,14 @@ namespace Ink_Canvas.Windows
|
|||||||
|
|
||||||
if (createImageMethod != null)
|
if (createImageMethod != null)
|
||||||
{
|
{
|
||||||
var imageTask = createImageMethod.Invoke(_mainWindow, new object[] { filePath }) as System.Threading.Tasks.Task<System.Windows.Controls.Image>;
|
var imageTask = createImageMethod.Invoke(_mainWindow, new object[] { filePath }) as System.Threading.Tasks.Task<FrameworkElement>;
|
||||||
if (imageTask != null)
|
if (imageTask != null)
|
||||||
{
|
{
|
||||||
var image = await imageTask;
|
var inserted = await imageTask;
|
||||||
if (image != null)
|
if (inserted != null)
|
||||||
{
|
{
|
||||||
image.Tag = filePath;
|
inserted.Tag = filePath;
|
||||||
await InsertImageToMainWindow(image, filePath);
|
await InsertImageToMainWindow(inserted, filePath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1185,9 +1186,9 @@ namespace Ink_Canvas.Windows
|
|||||||
}, DispatcherPriority.Normal);
|
}, DispatcherPriority.Normal);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async System.Threading.Tasks.Task InsertImageToMainWindow(System.Windows.Controls.Image image, string originalFilePath = null, bool saveToJson = true)
|
private async System.Threading.Tasks.Task InsertImageToMainWindow(FrameworkElement element, string originalFilePath = null, bool saveToJson = true)
|
||||||
{
|
{
|
||||||
if (_mainWindow == null || image == null) return;
|
if (_mainWindow == null || element == null) return;
|
||||||
|
|
||||||
// 确保在UI线程上执行
|
// 确保在UI线程上执行
|
||||||
await Application.Current.Dispatcher.InvokeAsync(() =>
|
await Application.Current.Dispatcher.InvokeAsync(() =>
|
||||||
@@ -1196,11 +1197,11 @@ namespace Ink_Canvas.Windows
|
|||||||
{
|
{
|
||||||
// 生成唯一名称
|
// 生成唯一名称
|
||||||
string timestamp = "img_" + DateTime.Now.ToString("yyyyMMdd_HH_mm_ss_fff");
|
string timestamp = "img_" + DateTime.Now.ToString("yyyyMMdd_HH_mm_ss_fff");
|
||||||
image.Name = timestamp;
|
element.Name = timestamp;
|
||||||
|
|
||||||
// 设置图片属性
|
// 设置图片属性
|
||||||
image.IsHitTestVisible = true;
|
element.IsHitTestVisible = true;
|
||||||
image.Focusable = false;
|
element.Focusable = false;
|
||||||
|
|
||||||
System.Windows.Controls.InkCanvas inkCanvas = null;
|
System.Windows.Controls.InkCanvas inkCanvas = null;
|
||||||
var inkCanvasField = _mainWindow.GetType().GetField("inkCanvas",
|
var inkCanvasField = _mainWindow.GetType().GetField("inkCanvas",
|
||||||
@@ -1274,7 +1275,7 @@ namespace Ink_Canvas.Windows
|
|||||||
// 如果在PPT模式下,记录图片和页面编号的关联,并保存图片路径
|
// 如果在PPT模式下,记录图片和页面编号的关联,并保存图片路径
|
||||||
if (currentSlideNumber > 0 && !string.IsNullOrEmpty(originalFilePath) && saveToJson)
|
if (currentSlideNumber > 0 && !string.IsNullOrEmpty(originalFilePath) && saveToJson)
|
||||||
{
|
{
|
||||||
_pptImages[image] = currentSlideNumber;
|
_pptImages[element] = currentSlideNumber;
|
||||||
|
|
||||||
// 添加到页面图片路径列表
|
// 添加到页面图片路径列表
|
||||||
if (!_pptImagePaths.ContainsKey(currentSlideNumber))
|
if (!_pptImagePaths.ContainsKey(currentSlideNumber))
|
||||||
@@ -1289,14 +1290,14 @@ namespace Ink_Canvas.Windows
|
|||||||
else if (currentSlideNumber > 0)
|
else if (currentSlideNumber > 0)
|
||||||
{
|
{
|
||||||
// 即使不保存到JSON,也要记录图片和页面编号的关联(用于翻页显示/隐藏)
|
// 即使不保存到JSON,也要记录图片和页面编号的关联(用于翻页显示/隐藏)
|
||||||
_pptImages[image] = currentSlideNumber;
|
_pptImages[element] = currentSlideNumber;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 先添加到画布(与MainWindow的实现保持一致)
|
// 先添加到画布(与MainWindow的实现保持一致)
|
||||||
inkCanvas.Children.Add(image);
|
inkCanvas.Children.Add(element);
|
||||||
|
|
||||||
// 等待图片加载完成后再进行后续处理
|
// 等待图片加载完成后再进行后续处理
|
||||||
image.Loaded += (s, args) =>
|
element.Loaded += (s, args) =>
|
||||||
{
|
{
|
||||||
Application.Current.Dispatcher.BeginInvoke(new Action(() =>
|
Application.Current.Dispatcher.BeginInvoke(new Action(() =>
|
||||||
{
|
{
|
||||||
@@ -1305,19 +1306,19 @@ namespace Ink_Canvas.Windows
|
|||||||
// 初始化TransformGroup
|
// 初始化TransformGroup
|
||||||
var initializeTransformMethod = _mainWindow.GetType().GetMethod("InitializeElementTransform",
|
var initializeTransformMethod = _mainWindow.GetType().GetMethod("InitializeElementTransform",
|
||||||
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
|
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
|
||||||
initializeTransformMethod?.Invoke(_mainWindow, new object[] { image });
|
initializeTransformMethod?.Invoke(_mainWindow, new object[] { element });
|
||||||
|
|
||||||
// 居中缩放
|
// 居中缩放
|
||||||
var centerMethod = _mainWindow.GetType().GetMethod("CenterAndScaleElement",
|
var centerMethod = _mainWindow.GetType().GetMethod("CenterAndScaleElement",
|
||||||
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
|
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
|
||||||
centerMethod?.Invoke(_mainWindow, new object[] { image });
|
centerMethod?.Invoke(_mainWindow, new object[] { element });
|
||||||
|
|
||||||
// 绑定事件处理器
|
// 绑定事件处理器
|
||||||
var bindEventsMethod = _mainWindow.GetType().GetMethod("BindElementEvents",
|
var bindEventsMethod = _mainWindow.GetType().GetMethod("BindElementEvents",
|
||||||
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
|
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
|
||||||
bindEventsMethod?.Invoke(_mainWindow, new object[] { image });
|
bindEventsMethod?.Invoke(_mainWindow, new object[] { element });
|
||||||
|
|
||||||
LogHelper.WriteLogToFile($"图片插入完成: {image.Name}, PPT页面: {currentSlideNumber}");
|
LogHelper.WriteLogToFile($"图片插入完成: {element.Name}, PPT页面: {currentSlideNumber}");
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -1333,7 +1334,7 @@ namespace Ink_Canvas.Windows
|
|||||||
if (timeMachine != null)
|
if (timeMachine != null)
|
||||||
{
|
{
|
||||||
var commitMethod = timeMachine.GetType().GetMethod("CommitElementInsertHistory");
|
var commitMethod = timeMachine.GetType().GetMethod("CommitElementInsertHistory");
|
||||||
commitMethod?.Invoke(timeMachine, new object[] { image });
|
commitMethod?.Invoke(timeMachine, new object[] { element });
|
||||||
}
|
}
|
||||||
|
|
||||||
// 切换到选择模式
|
// 切换到选择模式
|
||||||
@@ -1699,12 +1700,16 @@ namespace Ink_Canvas.Windows
|
|||||||
|
|
||||||
// 检查已存在的图片路径(通过Tag)
|
// 检查已存在的图片路径(通过Tag)
|
||||||
var existingImagePaths = new HashSet<string>();
|
var existingImagePaths = new HashSet<string>();
|
||||||
foreach (System.Windows.Controls.Image existingImage in inkCanvas.Children.OfType<System.Windows.Controls.Image>())
|
foreach (var existingImage in inkCanvas.Children.OfType<System.Windows.Controls.Image>())
|
||||||
{
|
{
|
||||||
if (existingImage.Tag is string tagPath && !string.IsNullOrEmpty(tagPath))
|
if (existingImage.Tag is string tagPath && !string.IsNullOrEmpty(tagPath))
|
||||||
{
|
|
||||||
existingImagePaths.Add(tagPath);
|
existingImagePaths.Add(tagPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
foreach (var existingPdf in inkCanvas.Children.OfType<PdfEmbeddedView>())
|
||||||
|
{
|
||||||
|
if (existingPdf.Tag is string tagPath && !string.IsNullOrEmpty(tagPath))
|
||||||
|
existingImagePaths.Add(tagPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 使用反射调用MainWindow的CreateAndCompressImageAsync方法
|
// 使用反射调用MainWindow的CreateAndCompressImageAsync方法
|
||||||
@@ -1733,17 +1738,17 @@ namespace Ink_Canvas.Windows
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
var imageTask = createImageMethod.Invoke(_mainWindow, new object[] { imagePath }) as System.Threading.Tasks.Task<System.Windows.Controls.Image>;
|
var imageTask = createImageMethod.Invoke(_mainWindow, new object[] { imagePath }) as System.Threading.Tasks.Task<FrameworkElement>;
|
||||||
if (imageTask != null)
|
if (imageTask != null)
|
||||||
{
|
{
|
||||||
var image = await imageTask;
|
var inserted = await imageTask;
|
||||||
if (image != null)
|
if (inserted != null)
|
||||||
{
|
{
|
||||||
// 保存原始文件路径到Tag
|
// 保存原始文件路径到Tag
|
||||||
image.Tag = imagePath;
|
inserted.Tag = imagePath;
|
||||||
|
|
||||||
// 插入图片(不保存路径,因为已经存在)
|
// 插入图片(不保存路径,因为已经存在)
|
||||||
await InsertImageToMainWindow(image, imagePath, false);
|
await InsertImageToMainWindow(inserted, imagePath, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -168,6 +168,12 @@
|
|||||||
"System.Text.Json": "8.0.5"
|
"System.Text.Json": "8.0.5"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"System.Runtime.WindowsRuntime": {
|
||||||
|
"type": "Direct",
|
||||||
|
"requested": "[4.7.0, )",
|
||||||
|
"resolved": "4.7.0",
|
||||||
|
"contentHash": "RQxUkf37fp7MSWbOfKRjUjyudyfZb2u79YY5i1s+d7vuD80A7kmr2YfefO0JprQUhanxSm8bhXigCVfX2kEh+w=="
|
||||||
|
},
|
||||||
"WebDav.Client": {
|
"WebDav.Client": {
|
||||||
"type": "Direct",
|
"type": "Direct",
|
||||||
"requested": "[2.9.0, )",
|
"requested": "[2.9.0, )",
|
||||||
@@ -247,11 +253,6 @@
|
|||||||
"System.Memory": "4.5.4"
|
"System.Memory": "4.5.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"System.ComponentModel.Annotations": {
|
|
||||||
"type": "Transitive",
|
|
||||||
"resolved": "5.0.0",
|
|
||||||
"contentHash": "dMkqfy2el8A8/I76n2Hi1oBFEbG1SfxD2l5nhwXV3XjlnOmwxJlQbYpJH4W51odnU9sARCSAgv7S3CyAFMkpYg=="
|
|
||||||
},
|
|
||||||
"System.Memory": {
|
"System.Memory": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "4.5.5",
|
"resolved": "4.5.5",
|
||||||
@@ -290,11 +291,6 @@
|
|||||||
"resolved": "4.3.0",
|
"resolved": "4.3.0",
|
||||||
"contentHash": "J4GUi3xZQLUBasNwZnjrffN8i5wpHrBtZoLG+OhRyGo/+YunMRWWtwoMDlUAIdmX0uRfpHIBDSV6zyr3yf00TA=="
|
"contentHash": "J4GUi3xZQLUBasNwZnjrffN8i5wpHrBtZoLG+OhRyGo/+YunMRWWtwoMDlUAIdmX0uRfpHIBDSV6zyr3yf00TA=="
|
||||||
},
|
},
|
||||||
"System.Runtime.WindowsRuntime": {
|
|
||||||
"type": "Transitive",
|
|
||||||
"resolved": "4.6.0",
|
|
||||||
"contentHash": "IWrs1TmbxP65ZZjIglNyvDkFNoV5q2Pofg5WO7I8RKQOpLdFprQSh3xesOoClBqR4JHr4nEB1Xk1MqLPW1jPuQ=="
|
|
||||||
},
|
|
||||||
"System.Runtime.WindowsRuntime.UI.Xaml": {
|
"System.Runtime.WindowsRuntime.UI.Xaml": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "4.6.0",
|
"resolved": "4.6.0",
|
||||||
@@ -352,19 +348,6 @@
|
|||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "4.5.0",
|
"resolved": "4.5.0",
|
||||||
"contentHash": "okurQJO6NRE/apDIP23ajJ0hpiNmJ+f0BwOlB/cSqTLQlw5upkf+5+96+iG2Jw40G1fCVCyPz/FhIABUjMR+RQ=="
|
"contentHash": "okurQJO6NRE/apDIP23ajJ0hpiNmJ+f0BwOlB/cSqTLQlw5upkf+5+96+iG2Jw40G1fCVCyPz/FhIABUjMR+RQ=="
|
||||||
},
|
|
||||||
"inkcanvas.pluginhost": {
|
|
||||||
"type": "Project",
|
|
||||||
"dependencies": {
|
|
||||||
"InkCanvas.PluginSdk": "[1.0.0, )"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"inkcanvas.pluginsdk": {
|
|
||||||
"type": "Project",
|
|
||||||
"dependencies": {
|
|
||||||
"Newtonsoft.Json": "[13.0.3, )",
|
|
||||||
"System.ComponentModel.Annotations": "[5.0.0, )"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
".NETFramework,Version=v4.7.2/win": {
|
".NETFramework,Version=v4.7.2/win": {
|
||||||
|
|||||||
Reference in New Issue
Block a user