首页 > 编程语言 >基于C#自动调整pdf注释框的方法

基于C#自动调整pdf注释框的方法

时间:2023-06-26 16:23:29浏览次数:39  
标签:C# text 注释 xfdf 字体 坐标 计算 pdf rect

众所周知 pdf 注释框是无法随着文字大小而自动调整宽高的,因此在网上搜索了很多文章,但并没有找到好的方法,于是打算使用程序自己写代码进行调整。

准备工作

要想自动调整注释框,首先得知道每个注释框的宽高,以及所属字体,是否加粗等信息。

所幸这些信息在 pdf 导出的注释文件(.xfdf)都有保存,这里不过多展开,以下是 xfdf 截取的部分代码

<freetext rect="177.595444,740.365417,262.641174,786.390137" creationdate="D:20230626143154+08'00'" name="656a7e33-a002-9fc9-5fe2-925bdd59d2e0" opacity="1" flags="print" date="D:20230626143256+08'00'" title="Administrator" subject="文本框" rotation="0" page="0" width="1" head="None" fringe="0,0,0,0">
<contents-richtext><body xmlns="http://www.w3.org/1999/xhtml" xmlns:xfa="http://www.xfa.org/schema/xfa-data/1.0/" xfa:APIVersion="Acrobat:7.0.0" xfa:spec="2.0.2" style="font-size:12.00pt;font-family:'Times New Roman'"><p><span style="text-decoration:;font-family:'Arial'">test</span><span style="text-decoration:;font-family:'宋体'">这是一个测试</span><span style="text-decoration:;font-family:'Arial'">
</span></p>
</body>
</contents-richtext>
<defaultappearance>1.000000 0.000000 0.000000 rg /Helv 12 Tf</defaultappearance>
<defaultstyle>text-decoration:;font-size:12.00pt;font-family:'Times New Roman'</defaultstyle></freetext>

freetext 表示文本框,其中 rect 记录了注释框的两个点坐标位置,以及 style 记录了字体的名称,是否加粗等信息。

得到了 xfdf 文件,我们就可以采用软件进行读取写入了(这里有坑,在后续介绍)。

读取XFDF文件

首先需要进行读写文件,xfdf 文件是基于XML格式的文件

//读取xfdf文件
XDocument document = XDocument.Load("blank.xfdf");

这里会遇到一个坑,带有xmlns属性时,无法正常读取文件,网上有提到命名空间的问题,这里图省事,直接使用replace删掉xmlns属性

<?xml version="1.0" encoding="UTF-8"?>
<xfdf xmlns="http://ns.adobe.com/xfdf/" xml:space="preserve">
<annots>
<freetext rect="177.595444,740.365417,262.641174,786.390137" creationdate="D:20230626143154+08'00'" name="656a7e33-a002-9fc9-5fe2-925bdd59d2e0" opacity="1" flags="print" date="D:20230626143256+08'00'" title="Administrator" subject="文本框" rotation="0" page="0" width="1" head="None" fringe="0,0,0,0">
<contents-richtext><body xmlns="http://www.w3.org/1999/xhtml" xmlns:xfa="http://www.xfa.org/schema/xfa-data/1.0/" xfa:APIVersion="Acrobat:7.0.0" xfa:spec="2.0.2" style="font-size:12.00pt;font-family:'Times New Roman'"><p><span style="text-decoration:;font-family:'Arial'">test</span><span style="text-decoration:;font-family:'宋体'">这是一个测试</span><span style="text-decoration:;font-family:'Arial'">
</span></p>
</body>
</contents-richtext>
<defaultappearance>1.000000 0.000000 0.000000 rg /Helv 12 Tf</defaultappearance>
<defaultstyle>text-decoration:;font-size:12.00pt;font-family:'Times New Roman'</defaultstyle></freetext>
</annots>
<f href=".\blank.pdf"/>
<ids original="8E059E4D73BCD0499DA82455FCF6FC3D" modified="8E059E4D73BCD0499DA82455FCF6FC3D"/>
</xfdf>

即替换掉以下两行代码为空

xmlns="http://ns.adobe.com/xfdf/"
xmlns="http://www.w3.org/1999/xhtml"

计算文字宽高

注意:这里计算文字宽高需要考虑中英文字体分开计算,本文未详细展开

这里采用了第三方库 iTextSharp 来计算字体宽高

//计算文字宽高,需要字体名称和需要计算的字符串两个参数
//这里需要注意fontname是实际的字体文件名
//对于Arial字体为arial.ttf,加粗版本arialbd.ttf
//宋体则为simsun.ttc,0
static Dictionary<string, double> CalculateFontSize(String fontname,String text) {
    if (fontname == null) { return new Dictionary<string, double>(); }
    //获取系统字体的字体路径
    string fontPath = Path.Combine("C:/WINDOWS/Fonts/", fontname);
    //创建指定字体
    Font font = new Font(BaseFont.CreateFont(fontPath, BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED));
    //创建文字段落
    var tmp = new iTextSharp.text.Paragraph(text, font);
    var basefont = tmp.Font.GetCalculatedBaseFont(true);
    //计算段落的字体宽度
    var width = basefont.GetWidthPoint(text, tmp.Font.CalculatedSize);
    //计算段落的字体高度
    var height = basefont.GetAscentPoint(text, tmp.Font.CalculatedSize) - basefont.GetDescentPoint(text, tmp.Font.CalculatedSize);
    //以字典形式返回结果
    Dictionary<string,double> fontSize = new Dictionary<string, double>() {
        { "width",width },
        { "height",height },
    };
return fontSize;
}

计算出字体宽高后,则需要计算出新的 rect 坐标,写入 xfdf 文件中

rect坐标的读写

提取坐标

提取 rect 坐标可遍历所有 freetext 后采用 freetext.Attribute("rect").Value 获得其文本结果

计算坐标

对于 pdf 坐标系是以左下角为坐标轴原点,x 轴向右为正方向,y 轴向上为正方向,详细可参考:itextpdf确定页面坐标的方式

pdf坐标轴示意图

对于 rect 坐标

rect="x1,y1,x2,y2"

rect 坐标

计算字符串宽度和高度只需要计算 x2,y1
即:rect="x1,y2-textHeight,x1+textWidth,y2"

这里计算 x2 和 y1 是考虑到文字左对齐且靠近顶部,因此只需要调整 x2 和 y1 的大小

同时需要考虑到文字与矩形边框有一定的边距,这里通过实验调整得到以下结果

//文字与矩形框之间剩余总宽度
private static double paddingWidth = 5d;
//文字与矩形框之间剩余总高度
private static double paddingHeight = 8.5d;

最后的rect坐标调整结果为

rect="x1,y2-(textHeight+paddingWidth),x1+(textWidth+paddingHeight),y2"

更新坐标

计算好坐标以后,即可使用 freetext.Attribute("rect").SetValue(rectString); 来更新坐标

保存XFDF文件

使用 document.Save('blank_new.xfdf'); 保存新的 xfdf 文件即可。

最后将新的 xfdf 文件导入空白无注释的 pdf 文件中即可看到调整的效果

后话

起初最想到的是使用 Python 进行自动调整注释框,没想到在计算字体宽高一直无法得到准确的结果导致卡了很久。

后面采用 C# 的 iTextSharp 库做了个计算宽高的命令行程序,然后使用 Python 的 subprocess 调用返回结果,结果发现效率太太太低了,注释一多,运行就得几分钟,然后直接全改为 C# 编写,于是有了这一片文章。

标签:C#,text,注释,xfdf,字体,坐标,计算,pdf,rect
From: https://www.cnblogs.com/tickltock/p/17505981.html

相关文章

  • Mybatis中Example的用法(QBC查询)
    QBC查询QueryByCriteria。Criteria是Criterion的复数形式。意思是:规则、标准、准则。在SQL语句中相当于查询条件。QBC查询是将查询条件通过Java对象进行模块化封装。Example简单介绍其实就是一个工具,自动帮你生成对应的代码1.example是Mybatis数据层框架中的一个工具,......
  • JavaScript进阶08笔记
    语法和数据类型声明JavaScript有三种声明方式。var声明一个变量,可选初始化一个值。let声明一个块作用域的局部变量,可选初始化一个值。const声明一个块作用域的只读常量。 声明变量你可以用以下三种方式声明变量:使用关键词var。例如varx=42。这个语......
  • JavaScript进阶09笔记
    错误处理异常处理语句你可以用throw语句抛出一个异常并且用try...catch语句捕获处理它。throw语句try...catch语句异常类型JavaScript可以抛出任意对象。然而,不是所有对象能产生相同的结果。尽管抛出数值或者字母串作为错误信息十分常见,但是通常用下列其中一种异......
  • Spring IoC有什么好处呢?
      来源   https://www.zhihu.com/question/23277575?utm_id=0   SpringIoC有什么好处呢? 作者:Mingqi链接:https://www.zhihu.com/question/23277575/answer/169698662来源:知乎著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。要了解控......
  • macos中回退键是Command+shift+z,我该如何改成Command+y?
    在使用macOS操作系统时,回退键的默认快捷键是Command+Shift+Z。然而,对于一些用户来说,这种组合键可能不太方便,因此他们希望将其改为其他组合键,例如Command+Y。如果你也想更改回退键的快捷键,请按照以下步骤进行操作。操作如下,打开系统设置-键盘 mac技巧及软件安 ......
  • git clone和fetch以及pull区别-9
    gitclone和fetch以及pull区别一.gitcloneGitclone适用于已有远程仓库,本机没有相关的本地仓库。使用方法:1.桌面/任意目录,右键单击,点击gitbash。2.输入:gitcloneurl(远程仓库地址)二.gitfetchGitfetch适用于,本机已有相关联的远程仓库。远程仓库中做了修改,本地也做了修改,需要拉......
  • 教职云智慧职教视频课件课程下载工具,如何在电脑端下载智慧职教视频课件PDF,PPT到本地
    一.安装智慧职教下载器1.获取学无止下载器https://www.xuewuzhi.cn/icve_downloader2.下载安装后,然后点击桌面快捷方式运行即可。注意:杀毒软件可能会阻止外部exe文件运行,并将其当做成病毒,直接添加信任即可,本软件绝对没有木马病毒。二.使用说明1.学无止下载器介绍学无止......
  • SpringCloud http大文件断点续传上传
    ​ 第一点:Java代码实现文件上传FormFilefile=manform.getFile();StringnewfileName= null;Stringnewpathname= null;StringfileAddre= "/numUp";try{    InputStreamstream=file.getInputStream();// 把文件读入    StringfilePath=request.......
  • 【问题解决】echart formatter 模板变量 精度
    遇到这样的精度问题这是之前的配置formatter:`{serie|{a}}\n{data|{c}}`+this.label,这样实现了不同样式,出现了jsnumber类型的精度问题formatter也可以返回模板,返回样式|模板的形式formatter:function(data){return(......
  • easyexcel 导入导出
    工具类-----------------------------------------------------publicclassExcelUtilextendsEasyExcelFactory{/***批量导入*@paraminputStream*@paramhead*@paramreadListener*/publicstaticvoidimportExcel(InputStreaminputS......