2024年5月

在同一页面中使用 System.Windows.Media 和 iTextSharp 绘制文本时出现位置不一致的问题,主要是因为两个库在处理文本的基线和坐标系统方面存在差异。要解决这个问题,我们需要了解这两个库在定位文本时的具体差异,并调整相应的代码以确保文本在视觉上的一致性。

  1. 坐标系统的差异
    System.Windows.Media: 通常使用的是一个基于屏幕左上角为原点的坐标系统,Y轴正方向向下。
    iTextSharp: 在PDF中,坐标系统的原点通常在页面左下角,Y轴正方向向上。
  2. 文本基线的处理
    System.Windows.Media: 文本的定位通常是基于左上角的边界框。
    iTextSharp: 文本的定位通常是基于文字的基线。

解决方案
要确保在使用 System.Windows.Media 和 iTextSharp 绘制相同大小和样式的文本时,文本的位置相匹配,您可以采取以下步骤:

A. 确定正确的文本位置
测量文本高度:

对于 iTextSharp,使用 BaseFont 的 GetAscentPoint 和 GetDescentPoint 方法来获取文本高度。
对于 System.Windows.Media,使用 FormattedText 类来计算文本的实际高度。
计算文本基线位置:

在 iTextSharp 中,使用 ascent 值来调整文本的 Y 坐标。
在 System.Windows.Media 中,需要计算文本框高度,并相应地调整 Y 坐标,使得文本的基线与 iTextSharp 生成的基线对齐。

1.Media 中的单位为px iTextSharp 单位为point
2.在 System.Windows.Media 中,文本的定位可能依赖于控件或具体的绘图命令,常常是以文本框的左上角为参考。在 iTextSharp 中,文本的定位通常是以文本的基线为参考。这意味着指定的Y坐标是文本基线的位置。
3.Media 坐标原点左上角 iTextSharp 坐标原点左下角

npm config set registry https://registry.npmmirror.com
npm config set registry http://mirrors.cloud.tencent.com/npm/

yarn config set registry https://registry.npmmirror.com
npm config set registry https://registry.npmmirror.com --global
npm config set disturl https://npmmirror.com/dist --global

1.创建 ViewModelLocator 类
右键点击 ViewModel 文件夹,选择 添加 > 类,命名为 ViewModelLocator.cs。
在 ViewModelLocator.cs 文件中,添加以下代码:

using CommonServiceLocator;
using GalaSoft.MvvmLight.Ioc;

namespace VideoWatermark_Premium.ViewModel
{
    public class ViewModelLocator
    {
        public ViewModelLocator()
        {
            ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);

            // Register ViewModels
            SimpleIoc.Default.Register<MainWindowViewModel>();
        }

        public MainWindowViewModel MainWindowViewModel
        {
            get { return ServiceLocator.Current.GetInstance<MainWindowViewModel>(); }
        }

        public static void Cleanup()
        {
            // TODO Clear the ViewModels
        }
    }
}

2.修改 App.xaml 文件
打开 App.xaml 文件。
修改 App.xaml 文件,添加 ViewModelLocator 资源:

<Application x:Class="VideoWatermark_Premium.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:vm="clr-namespace:VideoWatermark_Premium.ViewModel"
             StartupUri="MainWindow.xaml">
    <Application.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <!-- HandyControl 主题-->
                <ResourceDictionary Source="pack://application:,,,/HandyControl;component/Themes/SkinDefault.xaml"/>
                <ResourceDictionary Source="pack://application:,,,/HandyControl;component/Themes/Theme.xaml"/>
            </ResourceDictionary.MergedDictionaries>
            <!-- ViewModelLocator -->
            <vm:ViewModelLocator x:Key="Locator" />
        </ResourceDictionary>
    </Application.Resources>
</Application>

3.设置 MainWindow 的 DataContext
打开 MainWindow.xaml 文件。
设置 DataContext,使其绑定到 ViewModelLocator 的 MainWindowViewModel 属性:

<Window x:Class="VideoWatermark_Premium.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        DataContext="{Binding Source={StaticResource Locator}, Path=MainWindowViewModel}"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <TextBlock Text="{Binding WelcomeMessage}" VerticalAlignment="Center" HorizontalAlignment="Center" FontSize="24"/>
    </Grid>
</Window>

选择一个或者多个文件文件:Microsoft.WindowsAPICodePack.Dialogs.CommonOpenFileDialog
选择文件夹:Microsoft.WindowsAPICodePack.Dialogs.CommonOpenFileDialog
保存文件夹:Microsoft.WindowsAPICodePack.Dialogs.CommonSaveFileDialog

NuGet 包管理器安装安装 WindowsAPICodePack-Shell

选择一个或者多个文件: OpenFileDialog
保存文件夹:SaveFileDialog

Microsoft.Win32

选择一个或者多个文件:OpenFileDialog
选择文件夹:FolderBrowserDialog
保存文件夹:SaveFileDialog

System.Windows.Forms