我搜索找到一个用iTextSharp提取RightToLeft语言字符串的解决方案,但我找不到任何方法 . 是否可以使用iTextSharp从pdf文件中提取RightToLeft语言的字符串?谢谢
编辑:此代码有非常好的结果:
private void writePdf2()
{
using (var document = new Document(PageSize.A4))
{
var writer = PdfWriter.GetInstance(document, new FileStream(@"C:\Users\USER\Desktop\Test2.pdf", FileMode.Create));
document.Open();
FontFactory.Register("c:\\windows\\fonts\\tahoma.ttf");
var tahoma = FontFactory.GetFont("tahoma", BaseFont.IDENTITY_H);
var reader = new PdfReader(@"C:\Users\USER\Desktop\Test.pdf");
int intPageNum = reader.NumberOfPages;
string text = null;
for (int i = 1; i <= intPageNum; i++)
{
text = PdfTextExtractor.GetTextFromPage(reader, i, new LocationTextExtractionStrategy());
text = Encoding.UTF8.GetString(Encoding.UTF8.GetBytes(text.ToString()));
text = new UnicodeCharacterPlacement
{
Font = new System.Drawing.Font("Tahoma", 12)
}.Apply(text);
File.WriteAllText("page-" + i + "-text.txt", text.ToString());
}
reader.Close();
ColumnText.ShowTextAligned(
canvas: writer.DirectContent,
alignment: Element.ALIGN_RIGHT,
phrase: new Phrase(new Chunk("Test. Hello world. Hello people. سلام. کلمه سلام. سلام مردم", tahoma)),
//phrase: new Phrase(new Chunk(text, tahoma)),
x: 300,
y: 300,
rotation: 0,
runDirection: PdfWriter.RUN_DIRECTION_RTL,
arabicOptions: 0);
}
System.Diagnostics.Process.Start(@"C:\Users\USER\Desktop\Test2.pdf");
}
但是“短语:新词组(新词块(文本,tahoma))”对于PDF中的所有字符串都没有正确的输出 . 因此,我使用“PdfStamper”制作适合“iTextSharp”中“PdfReader”的PDF .
1 回答
重现问题
由于最初OP无法提供样本文件,我首先尝试使用iTextSharp本身生成的文件重现该问题 .
我的测试方法首先使用带有字符串常量的
ColumnText.ShowTextAligned
创建PDF,根据OP返回一个好的结果 . 然后它提取该文件的文本内容 . 最后,它创建了第二个PDF,其中包含使用带有字符串常量的良好ColumnText.ShowTextAligned
调用创建的行,然后使用带有提取字符串的ColumnText.ShowTextAligned
创建的几行,带有或不带有OP代码的后处理指令(UTF8编码和-decoding;应用UnicodeCharacterPlacement
)执行 .我无法立即找到OP使用的
UnicodeCharacterPlacement
类 . 所以我google了一下,发现了一个这样的类here . 我希望这基本上是OP使用的类 .最终结果:
从而,
我无法重现这个问题 . 对我来说,最后两个变体的阿拉伯语内容与原始行相同 . 特别是我无法观察到从"سلام"到"سالم"的切换 . 最有可能的PDF
C:\Users\USER\Desktop\Test.pdf
(OP从他的测试中提取文本)的内容在某种程度上是特殊的,因此从中提取的文本用该开关绘制 .将
UnicodeCharacterPlacement
类应用于提取的文本是必要的,以使其按正确的顺序排列 .另一条后处理线,
没有任何区别,不应该使用 .
为了进一步分析,我们需要PDF
C:\Users\USER\Desktop\Test.pdf
.检查salamword.pdf
最终OP可以提供PDF样本,salamword.pdf:
确实,我可以重现这种行为 . 所以我分析了阿拉伯文写作在里面编码的方式......
Some background information to start with:
PDF中的字体可以具有完全自定义编码(在手头的情况下) . 特别是嵌入式子集通常是通过在字符到来时选择代码来生成的,例如 . 页面上使用的给定字体中的第一个字符编码为
1
,第二个字符编码为2
,第三个字符编号为3
等 .因此,简单地提取绘制文本的代码根本没有多大帮助(参见下面的手头文件中的示例) . 但PDF中的字体可以带来一些额外的信息,允许提取器将代码映射到Unicode值 . 这些信息可能是
a ToUnicode map提供即时映射代码 - > Unicode代码点;
an Encoding 以字形名称的形式提供基本编码(例如 WinAnsiEncoding )及其差异;这些名称可能是标准名称或仅在手头字体的上下文中有意义的名称;
ActualText 结构元素或标记内容序列的条目 .
PDF规范描述了一种方法,该方法使用带有标准名称的 ToUnicode 和 Encoding 信息从PDF中提取文本,并在适用的情况下提供 ActualText 作为替代方法 . iTextSharp文本提取代码使用标准名称实现 ToUnicode / Encoding 方法 .
PDF规范中此上下文中的标准名称是从Adobe标准拉丁字符集中获取的字符名称和符号字体中的命名字符集 .
In the file at hand:
让我们看一下用Arial编写的行中的阿拉伯语文本 . 这里用于字形的代码是:
这看起来非常像使用如上所述的ad-hoc编码 . 因此,仅使用这些信息根本没有帮助 .
因此,让我们看一下嵌入式Arial子集的 ToUnicode 映射:
这将
01
映射到0020
,02
至0645
,03
至062f
,04
至0631
,08
至002e
等 . 但它不会将05
,06
,07
等映射到任何东西 .因此 ToUnicode Map 仅对某些代码有帮助 .
现在让我们看一下相关的编码
编码基于 WinAnsiEncoding ,但所有感兴趣的代码都在 Differences 中重新映射 . 在那里我们发现了许多标准的字形名称(即从Adobe标准拉丁字符集中获取的字符名称和符号字体中的命名字符集),如 space ,_ 279595, w , i , t 等;但我们也发现了几个非标准名称,如 uni0645 , uni06440627.fina 等 .
似乎有一个用于这些名称的方案, uni0645 表示Unicode代码点0645处的字符,而 uni06440627.fina 很可能代表Unicode代码点0644和0627处的某些最终形式的某些顺序的字符 . 但是,根据PDF规范提供的方法,这些名称对于文本提取仍然是非标准的 .
此外,文件中根本没有 ActualText 个条目 .
因此,仅提取“م . م . مدد”的原因是,仅对于这些字形,PDF中的标准PDF文本提取方法有适当的信息 .
顺便说一句,如果您从Adobe Reader中的文件中复制和粘贴,您将获得类似的结果,并且Adobe Reader具有相当好的标准文本提取方法的实现 .
TL;DR
样本文件不包含使用PDF规范描述的方法提取文本所需的信息,这是iTextSharp实现的方法 .