当前位置: 首页 > 知识库问答 >
问题:

使用iTextSharp从pdf文件中提取RightToLeft语言字符串

宋建本
2023-03-14

我试图找到一种用iTextSharp提取右到左语言字符串的解决方案,但找不到任何方法。是否可以使用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");
    }

但是短语: new Phrase(new Chunk(text, tahoma))并没有对PDF中的所有字符串都有正确的输出。因此,我使用PdfStamper制作了一个适用于iTextSharp中的PdfReader的PDF。

共有1个答案

闻人仲渊
2023-03-14

由于OP最初无法提供示例文件,我首先尝试用iTextSharp自己生成的文件重现该问题。

我的测试方法首先使用列文本创建PDF。ShowTextAligned与字符串常量对齐,根据OP返回一个好结果。然后提取该文件的文本内容。最后,它创建了第二个PDF,其中包含使用goodColumnText创建的一行。ShowTextAligned使用字符串常量调用,然后使用ColumnText创建几行。ShowTextAligned,使用从OP代码(UTF8编码和-解码;应用UnicodeCharacterPlacement)执行的带或不带后处理指令的提取字符串。

我无法立即找到OP使用的UnicodeCharacterPlacement类。所以我在谷歌上搜索了一下,在这里找到了一个这样的类。我希望这基本上就是OP使用的类。

public void ExtractTextLikeUser2509093()
{
    string rtlGood = @"C:\Temp\test-results\extract\rtlGood.pdf";
    string rtlGoodExtract = @"C:\Temp\test-results\extract\rtlGood.txt";
    string rtlFinal = @"C:\Temp\test-results\extract\rtlFinal.pdf";
    Directory.CreateDirectory(@"C:\Temp\test-results\extract\");

    FontFactory.Register("c:\\windows\\fonts\\tahoma.ttf");
    Font tahoma = FontFactory.GetFont("tahoma", BaseFont.IDENTITY_H);

    // A - Create a PDF with a good RTL representation
    using (FileStream fs = new FileStream(rtlGood, FileMode.Create, FileAccess.Write, FileShare.None))
    {
        using (Document document = new Document())
        {
            PdfWriter pdfWriter = PdfWriter.GetInstance(document, fs);
            document.Open();

            ColumnText.ShowTextAligned(
                        canvas: pdfWriter.DirectContent,
                        alignment: Element.ALIGN_RIGHT,
                        phrase: new Phrase(new Chunk("Test. Hello world. Hello people. سلام. کلمه سلام. سلام مردم", tahoma)),
                        x: 500,
                        y: 300,
                        rotation: 0,
                        runDirection: PdfWriter.RUN_DIRECTION_RTL,
                        arabicOptions: 0);
        }
    }

    // B - Extract the text for that good representation and add it to a new PDF
    String textA, textB, textC, textD;
    using (PdfReader pdfReader = new PdfReader(rtlGood))
    {
        textA = PdfTextExtractor.GetTextFromPage(pdfReader, 1, new LocationTextExtractionStrategy());
        textB = Encoding.UTF8.GetString(Encoding.UTF8.GetBytes(textA.ToString()));
        textC = new UnicodeCharacterPlacement
        {
            Font = new System.Drawing.Font("Tahoma", 12)
        }.Apply(textA);
        textD = new UnicodeCharacterPlacement
        {
            Font = new System.Drawing.Font("Tahoma", 12)
        }.Apply(textB);

        File.WriteAllText(rtlGoodExtract, textA + "\n\n" + textB + "\n\n" + textC + "\n\n" + textD + "\n\n");
    }
    using (FileStream fs = new FileStream(rtlFinal, FileMode.Create, FileAccess.Write, FileShare.None))
    {
        using (Document document = new Document())
        {
            PdfWriter pdfWriter = PdfWriter.GetInstance(document, fs);
            document.Open();

            ColumnText.ShowTextAligned(
                        canvas: pdfWriter.DirectContent,
                        alignment: Element.ALIGN_RIGHT,
                        phrase: new Phrase(new Chunk("Test. Hello world. Hello people. سلام. کلمه سلام. سلام مردم", tahoma)),
                        x: 500,
                        y: 600,
                        rotation: 0,
                        runDirection: PdfWriter.RUN_DIRECTION_RTL,
                        arabicOptions: 0);

            ColumnText.ShowTextAligned(
                        canvas: pdfWriter.DirectContent,
                        alignment: Element.ALIGN_RIGHT,
                        phrase: new Phrase(new Chunk(textA, tahoma)),
                        x: 500,
                        y: 550,
                        rotation: 0,
                        runDirection: PdfWriter.RUN_DIRECTION_RTL,
                        arabicOptions: 0);

            ColumnText.ShowTextAligned(
                        canvas: pdfWriter.DirectContent,
                        alignment: Element.ALIGN_RIGHT,
                        phrase: new Phrase(new Chunk(textB, tahoma)),
                        x: 500,
                        y: 500,
                        rotation: 0,
                        runDirection: PdfWriter.RUN_DIRECTION_RTL,
                        arabicOptions: 0);

            ColumnText.ShowTextAligned(
                        canvas: pdfWriter.DirectContent,
                        alignment: Element.ALIGN_RIGHT,
                        phrase: new Phrase(new Chunk(textC, tahoma)),
                        x: 500,
                        y: 450,
                        rotation: 0,
                        runDirection: PdfWriter.RUN_DIRECTION_RTL,
                        arabicOptions: 0);

            ColumnText.ShowTextAligned(
                        canvas: pdfWriter.DirectContent,
                        alignment: Element.ALIGN_RIGHT,
                        phrase: new Phrase(new Chunk(textD, tahoma)),
                        x: 500,
                        y: 400,
                        rotation: 0,
                        runDirection: PdfWriter.RUN_DIRECTION_RTL,
                        arabicOptions: 0);
        }
    }
}

最终结果是:

因此,

>

  • 我无法重现这个问题。对我来说,最后两个变体的阿拉伯内容看起来都与原始行相同。特别是,我无法观察到从 "سلام" 到 "سالم". 的切换。最有可能的是PDFC:\User\USER\Desktop\Test.pdf(OP从其中提取了测试中的文本)在某种程度上是特殊的,因此从它中提取的文本会使用该切换。

    UnicodeCharacterPlacement类应用于提取的文本是必要的,这样才能使其按正确的顺序排列。

    另一条后处理线,

    text = Encoding.UTF8.GetString(Encoding.UTF8.GetBytes(text.ToString()));
    

    没有任何区别,不应使用。

    为了进一步分析,我们需要PDFC:\Users\USER\Desktop\Test。pdf

    最终OP可以提供一个示例PDF,salamword.pdf:

    我用“PrimoPDF”创建了一个包含以下内容的PDF文件:“Test.Hello world.Hello people。

    接下来我读了这个PDF文件。然后我收到了这个输出:“Test.Hello world.Hello people.م.م1583;م”。

    事实上,我可以复制这种行为。所以我分析了阿拉伯文字的编码方式。。。

    以下是一些背景信息:

    PDF中的字体可以有一个完全自定义的编码(在目前的情况下确实有)。特别是嵌入式子集通常是通过选择字符来生成的,例如页面上使用的给定字体的第一个字符被编码为1,第二个不同的字符被编码为2,第三个不同的字符被编码为3等等。

    因此,简单地提取绘制文本的代码一点帮助都没有(参见下面手头文件中的示例)。但是PDF中的字体可以带来一些额外的信息,允许提取器将代码映射到Unicode值。这些信息可能是

    • 一个ToUnicode地图提供了一个即时的地图代码-

    PDF规范描述了一种使用ToUnicode和带有标准名称的编码信息从PDF中提取文本的方法,并在适用的情况下将ActualText作为替代方式呈现。iTextSharp文本提取代码使用标准名称实现ToUnicode/编码方法。

    PDF规范中的标准名称是取自Adobe标准拉丁字符集的字符名称,以及符号字体中的命名字符集。

    在手头的文件中:

    让我们看看用Arial写的行中的阿拉伯文本。这里用于字形的代码是:

    01 02 03 04 05 01 02 06 07 01 08 02 06 07 01 09 05 00B01 08 02 06 07

    这看起来很像使用了如上所述的特殊编码。因此,仅使用这些信息毫无帮助。

    因此,让我们看看嵌入式Arial子集的ToUnicode映射:

    <01><01><0020>
    <02><02><0645>
    <03><03><062f>
    <04><04><0631>
    <08><08><002e>
    <0c><0c><0028>
    <0d><0d><0077>
    <0e><0e><0069>
    <0f><0f><0074>
    <10><10><0068>
    <11><11><0041>
    <12><12><0072>
    <13><13><0061>
    <14><14><006c>
    <15><15><0066>
    <16><16><006f>
    <17><17><006e>
    <18><18><0029> 
    

    这将01映射到002002映射到064503映射到062f04映射到063108映射到002e,等等。但它不会将050607映射到任何东西。

    所以ToUnicode映射只对某些代码有帮助。

    现在让我们看看相关的编码

    29 0 obj
    <</Type/Encoding
      /BaseEncoding/WinAnsiEncoding
      /Differences[ 1
        /space/uni0645/uni062F/uni0631
        /uni0645.init/uni06440627.fina/uni0633.init/period
        /uni0647.fina/uni0644.medi/uni06A9.init/parenleft
        /w/i/t/h
        /A/r/a/l
        /f/o/n/parenright ]
    >>
    endobj 
    

    编码是基于WinAnsiEn编码的,但是所有感兴趣的代码都在差异中重新映射。在那里我们找到了许多标准字形名称(即取自Adobe标准拉丁字符集和符号字体中命名字符集的字符名称),如空间、句号、w、i、t等。;但是我们也找到了几个非标准名称,如uni0645、uni06440627.fina等。

    这些名称似乎使用了一个方案,uni0645表示Unicode代码点0645处的字符,uni06440627。fina很可能以某种最终形式以某种顺序表示Unicode代码点0644和0627处的字符。但根据PDF规范提供的方法,这些名称对于文本提取来说仍然是非标准的。

    此外,文件中根本没有ActualText条目。

    因此,只提取“م.م.مدم”的原因是,只有对于这些字形,PDF中才有标准PDF文本提取方法的适当信息。

    顺便说一下,如果你收到了

    TL;博士

    示例文件根本不包含使用PDF规范描述的方法提取文本所需的信息,该方法是由iTextSharp实现的。

  •  类似资料:
    • 问题内容: 我需要使用iText从pdf文件中提取文本。 问题是:一些pdf文件包含2列,当我提取文本时,我得到一个文本文件,其中的列作为结果合并(即同一行中两列的文本) 这是代码: 你能帮我完成这个任务吗? 问题答案: 我是iText文本提取子系统的作者。您需要做的是开发自己的文本提取策略(如果您看一下如何实现的话,就会发现您可以提供可插拔的策略)。 您将如何确定列的开始和停止位置完全取决于您-

    • 我有一个签名的PDF文件。有了这个功能,它利用了iTextSharp库,我找到了证书p7m签名: 现在...我如何提取与签名相关的图像(位图)?可能吗?谢谢,路易吉

    • 问题内容: 我正在寻找有关如何使用带有Python的PDFMiner从PDF文件提取文本的文档 或 示例。 看来PDFMiner更新了他们的API,我发现的所有相关示例都包含过时的代码(类和方法已更改)。我发现的那些使从PDF文件提取文本的任务更加容易的库正在使用旧的PDFMiner语法,因此我不确定如何执行此操作。 照原样,我只是在查看源代码,以查看是否可以解决。 问题答案: 这是一个使用当前版

    • 问题内容: 我正在尝试使用提取此 PDF文件中包含的文本。 我正在使用PyPDF2模块,并具有以下脚本: 运行代码时,得到以下输出,该输出与PDF文档中包含的输出不同: 如何提取PDF文档中的文本? 问题答案: 要从PDF提取文本,请使用以下代码

    • 我有一个列表。pdf,ppt,pptx,xls,xlsx,doc和。docx文件,现在想在这些文件中查找电子邮件地址。我的问题是如何从这些文件中智能地提取计划文本。目前我正在使用Apache POI,我对每种类型的文件都有一个单一的方法,是否有一个更短、更优雅的位置来做这件事?也许还可以处理。ODT、.ODP、.ODS文件?如何从。pdf,ppt,pptx,xls,xlsx,doc和.docx文件

    • 问题内容: 我想使用Apache PDFBox从给定的PDF文件中提取文本。 我写了这段代码: 但是,出现以下错误: 我在类路径中添加了pdfbox-1.8.5.jar和fontbox-1.8.5.jar。 编辑 我添加到程序的开头。 我运行了它,然后出现了与上述相同的错误,并且未出现在控制台中。 因此,我认为我对类路径或其他东西有疑问。 谢谢。 问题答案: 我执行了您的代码,它工作正常。也许您的