如何使用iTextsharp突出显示pdf文件中的文本或单词?

时间:2011-06-29 15:33:09

标签: pdf c#-2.0 itextsharp

我需要在现有的pdf文件中搜索一个单词,我想突出显示文字或单词

并保存pdf文件

我有一个想法使用PdfAnnotation.CreateMarkup我们可以找到文本的位置,我们可以添加bgcolor ...但我不知道如何实现它:(

请帮帮我

5 个答案:

答案 0 :(得分:4)

这是“声音容易但实际上非常复杂”的事情之一。请参阅Mark的帖子herehere。最终你可能会被指向LocationTextExtractionStrategy。祝好运!如果你真的知道如何把它发布在这里,有几个人想知道你在想什么!

答案 1 :(得分:4)

我已经找到了如何做到这一点,以防万一有人需要从PDF文档中获取带有位置(坐标)的单词或句子,你会发现这个例子Project HERE ,我使用VB.NET 2010。请记住在此项目中添加对iTextSharp DLL的引用。

我添加了自己的TextExtraction策略类,基于Class LocationTextExtractionStrategy。我专注于TextChunks,因为他们已经有了这些坐标。

有一些已知的限制,例如:

  • 不允许多行搜索(短语),只允许使用字符/单词或单行句子。
  • 无法使用旋转文字。
  • 我没有测试具有横向页面方向的PDF,但我认为可能需要对其进行一些修改。
  • 如果你需要在水印上绘制这个HighLight /矩形,你需要添加/修改一些代码,但只需要在Form中编码,这与文本/位置提取过程无关。

答案 2 :(得分:1)

@Jcis,我实际上使用您的示例作为起点管理了一个处理多个搜索的解决方法。我使用你的项目作为c#项目的参考,并改变了它的作用。而不仅仅是突出显示我实际上是在搜索词周围绘制一个白色矩形,然后使用矩形坐标,放置一个表单域。我还必须将contentbyte写入模式交换为getovercontent,以便完全阻止搜索到的文本。我实际上做的是创建一个搜索词的字符串数组,然后使用for循环,我创建了尽可能多的不同文本字段。

        Test.Form1 formBuilder = new Test.Form1();

        string[] fields = new string[] { "%AccountNumber%", "%MeterNumber%", "%EmailFieldHolder%", "%AddressFieldHolder%", "%EmptyFieldHolder%", "%CityStateZipFieldHolder%", "%emptyFieldHolder1%", "%emptyFieldHolder2%", "%emptyFieldHolder3%", "%emptyFieldHolder4%", "%emptyFieldHolder5%", "%emptyFieldHolder6%", "%emptyFieldHolder7%", "%emptyFieldHolder8%", "%SiteNameFieldHolder%", "%SiteNameFieldHolderWithExtraSpace%" };
        //int a = 0;
        for (int a = 0; a < fields.Length; )
        {
            string[] fieldNames = fields[a].Split('%');
            string[] fieldName = Regex.Split(fieldNames[1], "Field");
            formBuilder.PDFTextGetter(fields[a], StringComparison.CurrentCultureIgnoreCase, htmlToPdf, finalhtmlToPdf, fieldName[0]);
            File.Delete(htmlToPdf);
            System.Array.Clear(fieldNames, 0, 2);
            System.Array.Clear(fieldName, 0, 1);
            a++;
            if (a == fields.Length)
            {
                break;
            }
            string[] fieldNames1 = fields[a].Split('%');
            string[] fieldName1 = Regex.Split(fieldNames1[1], "Field");
            formBuilder.PDFTextGetter(fields[a], StringComparison.CurrentCultureIgnoreCase, finalhtmlToPdf, htmlToPdf, fieldName1[0]);
            File.Delete(finalhtmlToPdf);
            System.Array.Clear(fieldNames1, 0, 2);
            System.Array.Clear(fieldName1, 0, 1);
            a++;
        }

它反映了你的示例中的PDFTextGetter函数在两个文件之间来回反复,直到我完成了成品。它工作得很好,没有你的初始项目就不可能,所以谢谢你。我也改变了你的VB来做像这样的文本字段映射;

           For Each rect As iTextSharp.text.Rectangle In MatchesFound
                cb.Rectangle(rect.Left, rect.Bottom + 1, rect.Width, rect.Height + 4)
                Dim field As New TextField(stamper.Writer, rect, FieldName & Fields)
                Dim form = stamper.AcroFields
                Dim fieldKeys = form.Fields.Keys
                stamper.AddAnnotation(field.GetTextField(), page)
                Fields += 1
            Next

我想我会与你的项目分享我作为骨干的事情。它甚至会增加字段名称,因为我需要它们。我还必须为你的函数添加一个新参数,但这不值得在这里列出。再次感谢您的良好开端。

答案 3 :(得分:1)

谢谢Jcis!

经过几个小时的研究和思考,我找到了解决方案,帮助我解决了问题。

有2个小错误。

首先:压模需要在读者面前关闭,否则会引发异常。

this

第二:当搜索到的文本位于引用文本的最后一行时,您的解决方案不起作用。

Public Sub PDFTextGetter(ByVal pSearch As String, ByVal SC As StringComparison, ByVal SourceFile As String, ByVal DestinationFile As String)
    Dim stamper As iTextSharp.text.pdf.PdfStamper = Nothing
    Dim cb As iTextSharp.text.pdf.PdfContentByte = Nothing

    Me.Cursor = Cursors.WaitCursor
    If File.Exists(SourceFile) Then
        Dim pReader As New PdfReader(SourceFile)

        stamper = New iTextSharp.text.pdf.PdfStamper(pReader, New System.IO.FileStream(DestinationFile, FileMode.Create))
        PB.Value = 0 : PB.Maximum = pReader.NumberOfPages
        For page As Integer = 1 To pReader.NumberOfPages
            Dim strategy As myLocationTextExtractionStrategy = New myLocationTextExtractionStrategy

            'cb = stamper.GetUnderContent(page)
            cb = stamper.GetOverContent(page)
            Dim state As New PdfGState()
            state.FillOpacity = 0.3F
            cb.SetGState(state)

            'Send some data contained in PdfContentByte, looks like the first is always cero for me and the second 100, but i'm not sure if this could change in some cases
            strategy.UndercontentCharacterSpacing = cb.CharacterSpacing
            strategy.UndercontentHorizontalScaling = cb.HorizontalScaling

            'It's not really needed to get the text back, but we have to call this line ALWAYS, 
            'because it triggers the process that will get all chunks from PDF into our strategy Object
            Dim currentText As String = PdfTextExtractor.GetTextFromPage(pReader, page, strategy)

            'The real getter process starts in the following line
            Dim MatchesFound As List(Of iTextSharp.text.Rectangle) = strategy.GetTextLocations(pSearch, SC)

            'Set the fill color of the shapes, I don't use a border because it would make the rect bigger
            'but maybe using a thin border could be a solution if you see the currect rect is not big enough to cover all the text it should cover
            cb.SetColorFill(BaseColor.PINK)

            'MatchesFound contains all text with locations, so do whatever you want with it, this highlights them using PINK color:

            For Each rect As iTextSharp.text.Rectangle In MatchesFound
                ' cb.Rectangle(rect.Left, rect.Bottom, rect.Width, rect.Height)
                cb.SaveState()
                cb.SetColorFill(BaseColor.YELLOW)
                cb.Rectangle(rect.Left, rect.Bottom, rect.Width, rect.Height)
                cb.Fill()
                cb.RestoreState()
            Next
            'cb.Fill()

            PB.Value = PB.Value + 1
        Next
        stamper.Close()
        pReader.Close()
    End If
    Me.Cursor = Cursors.Default

End Sub

答案 4 :(得分:0)

我将 Jcis 的VB项目转换为WpfApplication C#(谷歌驱动器中的文件),甚至应用 Boris 的错误修正,但该项目没有运行。 非常感谢能够理解程序算法的人,修复它。