【问题标题】:Highlight words in a pdf using itextsharp, not displaying highlighted word in browser使用 itextsharp 突出显示 pdf 中的单词,而不是在浏览器中显示突出显示的单词
【发布时间】:2015-11-27 07:22:40
【问题描述】:

使用 itextsharp 在浏览器中未显示突出显示的字词。

Adobe

浏览器

代码

 List<iTextSharp.text.Rectangle> MatchesFound = strategy.GetTextLocations(splitText[i].Trim(), StringComparison.CurrentCultureIgnoreCase);
                    foreach (Rectangle rect in MatchesFound)
                    {
                        float[] quad = { rect.Left - 3.0f, rect.Bottom, rect.Right, rect.Bottom, rect.Left - 3.0f, rect.Top + 1.0f, rect.Right, rect.Top + 1.0f };
                        //Create our hightlight
                        PdfAnnotation highlight = PdfAnnotation.CreateMarkup(stamper.Writer, rect, null, PdfAnnotation.MARKUP_HIGHLIGHT, quad);
                        //Set the color
                        highlight.Color = BaseColor.YELLOW;
                       
                        //Add the annotation
                        stamper.AddAnnotation(highlight, pageno);
                        
                    }

请帮我解决这个问题。

更新代码

  private void highlightPDF()
{
    //Create a simple test file
    string outputFile = Server.MapPath("~/pdf/16193037V_Dhana-FI_NK-QA_Completed.pdf");
    string filename = "HL" + Convert.ToString(Session["Filename"]) + ".pdf";
    Session["Filename"] = "HL" + Convert.ToString(Session["Filename"]);
    //Create a new file from our test file with highlighting
    string highLightFile = Server.MapPath("~/pdf/" + filename);

    //Bind a reader and stamper to our test PDF

    PdfReader reader = new PdfReader(outputFile);
    iTextSharp.text.pdf.PdfContentByte canvas;
    int pageno = Convert.ToInt16(txtPageno.Text);
    using (FileStream fs = new FileStream(highLightFile, FileMode.Create, FileAccess.Write, FileShare.None))
    {
        using (PdfStamper stamper = new PdfStamper(reader, fs))
        {
            canvas = stamper.GetUnderContent(pageno);
            myLocationTextExtractionStrategy strategy = new myLocationTextExtractionStrategy();
            strategy.UndercontentCharacterSpacing = canvas.CharacterSpacing;
            strategy.UndercontentHorizontalScaling = canvas.HorizontalScaling;

            string currentText = PdfTextExtractor.GetTextFromPage(reader, pageno, strategy);
            string text = txtHighlight.Text.Replace("\r\n", "").Replace("\\n", "\n").Replace("  ", " ");
            string[] splitText = text.Split(new string[] { "\n" }, StringSplitOptions.RemoveEmptyEntries);
            for (int i = 0; i < splitText.Length; i++)
            {
                List<iTextSharp.text.Rectangle> MatchesFound = strategy.GetTextLocations(splitText[i].Trim(), StringComparison.CurrentCultureIgnoreCase);
                foreach (Rectangle rect in MatchesFound)
                {
                    canvas.SaveState();
                    canvas.SetColorFill(BaseColor.YELLOW);
                    canvas.Rectangle(rect);
                    canvas.Fill();
                    canvas.RestoreState();                      
                }
            }

        }
    }
    reader.Close();      


}

它没有突出显示文本。我传递了文本和页码以突出显示文本。

【问题讨论】:

  • 这不是 iText 的问题。这是您在浏览器中使用的 PDF 查看器的问题,而您不知道是哪个 PDF 查看器。它可能是 Chrome 的 PDF 查看器;在这种情况下,请将其设为 Chrome PDF 查看器问题。它可以是 Firefox 中的 pdf.js;在这种情况下,将其设为 pdf.js 问题。不要将 PDF 查看器的缺陷归咎于 iTextSharp。
  • 我也在 pdf.js 和 chrome 浏览器中测试过
  • 所以您已经确定 Chrome PDF 查看器和 pdf.js 都完全忽略了标记注释。您是否询问过 pdf.js 和 Chrome 的开发人员该诊断是否正确?您是否询问过他们计划何时解决该问题?
  • 我参考了这篇文章stackoverflow.com/questions/29032422/… 他们说你已经部分得到了答案,只是那些 PDF 渲染器不完全支持整个 PDF 语法。具体来说,(这只是一个有根据的猜测)似乎这些渲染需要为这些注释存在一个外观条目。
  • 好的,所以你有你的答案。现在只需等待 Chrome 和 pdf.js 开发人员通过正确实施 ISO-32000-1 来满足您的要求。

标签: c# itextsharp syntax-highlighting


【解决方案1】:

首先...

为什么 OP 的(更新的)代码不起作用

实际上有两个因素。

首先,OP的代码中有一个问题,要在他使用的路径中添加一个矩形

canvas.Rectangle(rect);

不幸的是,这不是他所期望的:Rectangle 类具有超出矩形坐标的多个属性,有关所选边框、边框颜色和内部颜色的最重要信息,PdfContentByte.Rectangle(Rectangle) 根据那些属性。

不过,在本例中,rect 仅用于传输矩形的坐标,因此这些附加属性都是falsenull。因此,canvas.Rectangle(rect) 什么都不做!

OP 应该使用

canvas.Rectangle(rect.Left, rect.Bottom, rect.Width, rect.Height);

这里。

此外,@Bruno 在他的回答中提到了

请注意,如果您将黄色矩形添加到不透明的形状下(例如,在图像下),您将看不到它。

不幸的是,这里的情况正是如此:文档实际上是扫描文档,每一页都是一个页面填充图像,在其下绘制等效文本(可能在 OCR 之后)以允许文本复制和粘贴。

因此,无论 OP 的代码可能在 UnderContent 上绘制什么,它都会被该图像隐藏。

因此,让我们尝试一些不同的东西......

如何让它发挥作用

@Bruno 在他的回答中也指出了这种情况的解决方案:

在这种情况下,您可以在现有内容的顶部添加一个透明矩形

根据这个建议我们替换

canvas = stamper.GetUnderContent(pageno);

通过

canvas = stamper.GetOverContent(pageno);

PdfGState state = new PdfGState();
state.FillOpacity = .3f;
canvas.SetGState(state);

在我们得到的第三个文档页面上选择“支持”一词:

这里的黄色很淡。

使用Opacity.6 代替我们得到

现在黄色更浓了,但文字开始变淡。

对于这样的任务,我实际上更喜欢使用混合模式变暗。这可以通过使用

state.BlendMode = new PdfName("Darken");

而不是state.FillOpacity = .3f。这导致

这个 IMO 看起来更好。

客户是如何做到的

OP评论了

客户已提供 pdf。在那里,他们突出显示文本,突出显示的文本显示在浏览器中

客户端的PDF实际上使用了注释,就像他原始代码中的OP一样,但相比之下,客户端的每个注释都包含一个外观流,而iText生成的高亮注释则没有。

提供外观是可选的,如果没有提供外观,PDF 查看器确实应该生成外观。但显然,有许多 PDF 查看器依赖 PDF 带来的外观。

顺便说一下,客户端 PDF 中的外观实际上使用了混合模式 Multiply。对于底层的白色和黑色,DarkenMultiply 具有相同的结果。

使其与注释一起工作

在评论中,OP 想知道

请再问一个问题,如果用户错误地突出显示,那么如何去除黄色(或将黄色变为白色)?我将黄色更改为白色,但它不起作用。 canvas.SetColorFill(BaseColor.WHITE);

撤消对页面内容的更改通常比撤消添加的注释更困难。因此,让我们让 OP 的原始代码也可以工作,即在高亮注释中添加外观流。

正如 OP 在另一条评论中报告的那样,他第一次尝试添加外观流失败了:

PdfAppearance appearance = PdfAppearance.CreateAppearance(stamper.Writer, rect.Width, rect.Height);
appearance.Rectangle(rect.Left, rect.Bottom, rect.Width, rect.Height);
appearance.SetColorFill(BaseColor.WHITE);
appearance.Fill();
highlight.SetAppearance( PdfAnnotation.APPEARANCE_NORMAL, appearance );
stamper.AddAnnotation(highlight, pageno);

但它不起作用。

他尝试的问题是:

  • 外观模板的原点在注释区的左下角,而不是在页面的左下角。因此,要为相关区域着色,矩形的左下角必须位于 (0, 0)。
  • 严格来说,颜色必须在开始构建路径之前设置。
  • 应使用与白色不同的颜色来突出显示。
  • 应使用透明度或适当的呈现模式,以使原始的、标记文本透出。

因此,下面的代码展示了如何做到这一点。

private void highlightPDFAnnotation(string outputFile, string highLightFile, int pageno, string[] splitText)
{
    PdfReader reader = new PdfReader(outputFile);
    iTextSharp.text.pdf.PdfContentByte canvas;
    using (FileStream fs = new FileStream(highLightFile, FileMode.Create, FileAccess.Write, FileShare.None))
    {
        using (PdfStamper stamper = new PdfStamper(reader, fs))
        {
            myLocationTextExtractionStrategy strategy = new myLocationTextExtractionStrategy();
            strategy.UndercontentHorizontalScaling = 100;

            string currentText = PdfTextExtractor.GetTextFromPage(reader, pageno, strategy);
            for (int i = 0; i < splitText.Length; i++)
            {
                List<iTextSharp.text.Rectangle> MatchesFound = strategy.GetTextLocations(splitText[i].Trim(), StringComparison.CurrentCultureIgnoreCase);
                foreach (Rectangle rect in MatchesFound)
                {
                    float[] quad = { rect.Left - 3.0f, rect.Bottom, rect.Right, rect.Bottom, rect.Left - 3.0f, rect.Top + 1.0f, rect.Right, rect.Top + 1.0f };
                    //Create our hightlight
                    PdfAnnotation highlight = PdfAnnotation.CreateMarkup(stamper.Writer, rect, null, PdfAnnotation.MARKUP_HIGHLIGHT, quad);
                    //Set the color
                    highlight.Color = BaseColor.YELLOW;

                    PdfAppearance appearance = PdfAppearance.CreateAppearance(stamper.Writer, rect.Width, rect.Height);
                    PdfGState state = new PdfGState();
                    state.BlendMode = new PdfName("Multiply");
                    appearance.SetGState(state);
                    appearance.Rectangle(0, 0, rect.Width, rect.Height);
                    appearance.SetColorFill(BaseColor.YELLOW);
                    appearance.Fill();

                    highlight.SetAppearance(PdfAnnotation.APPEARANCE_NORMAL, appearance);

                    //Add the annotation
                    stamper.AddAnnotation(highlight, pageno);
                }
            }
        }
    }
    reader.Close();
}

Chrome 也会显示这些注释,并且作为注释可以轻松删除。

【讨论】:

  • 很好的答案,感谢您在我在布鲁塞尔开会时填写,@mkl。
  • 非常感谢您的大力帮助。它工作正常。再次感谢您的时间和精力。
  • 请再提出一个疑问,如果用户错误地突出显示,那么如何去除黄色(或将黄色变为白色)?我将黄色更改为白色,但它不起作用。 canvas.SetColorFill(BaseColor.WHITE);
  • 在使用注解时删除肯定更容易。可能您应该将标记绘图代码应用到模板并将该模板附加到注释。
  • 如果您不介意,请提供代码。我用你上面的代码画了一个矩形。
【解决方案2】:

您正在使用标记注释来突出显示文本。那太棒了!您的代码和 iText 都没有问题。但是:并非所有 PDF 查看器都支持该功能。

如果您想在每个 PDF 查看器中看到突出显示的文本,一个(次优)解决方法可能是在现有内容下的内容流中添加一个黄色矩形(假设现有内容不透明)。

这在HighLightByAddingContent 示例中得到了证明:

public void manipulatePdf(String src, String dest) throws IOException, DocumentException {
    PdfReader reader = new PdfReader(src);
    PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(dest));
    PdfContentByte canvas = stamper.getUnderContent(1);
    canvas.saveState();
    canvas.setColorFill(BaseColor.YELLOW);
    canvas.rectangle(36, 786, 66, 16);
    canvas.fill();
    canvas.restoreState();
    stamper.close();
    reader.close();
}

在此示例中,我们获取一个名为 hello.pdf 的文件,并添加一个黄色矩形,结果为文件 hello_highlighted.pdf

请注意,如果将黄色矩形添加到不透明的形状下(例如,在图像下),您将看不到它。在这种情况下,您可以在现有内容的顶部添加一个透明矩形

更新:我的示例是用 Java 编写的。开发人员将其移植到 C# 应该不是问题。只需将一些小写字母更改为大写字母即可。例如。 stamper.GetUnderContent(1) 代替 stamper.getUnderContent(1)canvas.SaveState() 代替 canvas.saveState(),等等。

【讨论】:

  • 感谢您的帮助。我在问题中更新了我的代码。它没有突出显示。错误是什么?请帮帮我。
  • 我从stackoverflow.com/questions/6523243/… answer 2 中获取 myLocationTextExtractionStrategy 课程
  • 如果您共享了示例 PDF,您的问题可能会被重现。因此,请分享它。此外,客户提供了一个pdf。在那里,他们突出显示了文本,突出显示的文本显示在浏览器中 - 如果您还共享了他们的 PDF,我们可以知道他们使用什么技术以及该技术是否也适用于 iText。
  • @Karthik 有可能吗? - 是的,看我的回答。
  • Bruno Lowagie,感谢您的大力帮助和支持。
猜你喜欢
  • 2012-07-27
  • 2014-08-07
  • 2018-08-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-11-01
  • 1970-01-01
相关资源
最近更新 更多