使用 itextsharp 突出显示 pdf 中的单词,而不是在浏览器中显示突出显示的单词
Highlight words in a pdf using itextsharp, not displaying highlighted word in browser
在使用 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 查看器中看到突出显示的文本,(次优)解决方法可能是在内容流 现有内容下方添加一个黄色矩形(假设现有内容不是不透明的)。
这在 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 and we add a yellow rectangle, with the file hello_highlighted.pdf 的文件作为结果。
请注意,如果您将黄色矩形添加到不透明的形状下(例如图像下),您将看不到它。在这种情况下,您可以在 现有内容之上添加一个透明矩形 。
更新:我的例子是用Java写的。开发人员将其移植到 C# 应该不是问题。这只是将一些小写字母变成大写字母的问题。例如。 stamper.GetUnderContent(1)
代替 stamper.getUnderContent(1)
,canvas.SaveState()
代替 canvas.saveState()
,依此类推。
首先...
为什么 OP 的(更新的)代码不起作用
其实有两个因素。
首先,OP的代码中有一个问题,要在他使用的路径中添加一个矩形
canvas.Rectangle(rect);
不幸的是,这不是他所期望的:Rectangle
class 有多个属性,不仅仅是矩形的坐标,关于选定边框、边框颜色和内部颜色的最重要信息,以及PdfContentByte.Rectangle(Rectangle)
根据这些属性绘制一个矩形。
不过,在手头的例子中,rect
仅用于传输矩形的坐标,因此这些附加属性都是 false
或 null
。因此,canvas.Rectangle(rect)
什么都不做!
OP 应该使用
canvas.Rectangle(rect.Left, rect.Bottom, rect.Width, rect.Height);
这里。
此外,@Bruno在他的回答中提到
Note that you won't see the yellow rectangle if you add it under an opaque shape (e.g. under an image).
不幸的是,这里就是这种情况:文档实际上是一个扫描文档,每一页都是一个页面填充图像,在其下方绘制了等效文本(可能在 OCR 之后)以允许文本复制和粘贴。
因此,无论 OP 的代码可能在 UnderContent
上绘制什么,它都将被该图像隐藏。
因此,让我们尝试一些不同的东西...
如何让它发挥作用
@Bruno 在他的回答中也指出了这种情况的解决方案:
In that case, you could add a transparent rectangle on top of the existing content.
我们根据这个建议替换
canvas = stamper.GetUnderContent(pageno);
来自
canvas = stamper.GetOverContent(pageno);
PdfGState state = new PdfGState();
state.FillOpacity = .3f;
canvas.SetGState(state);
在第三个文档页面上选择单词 "support" 我们得到:
这里的黄色很淡
使用 .6
的 Opacity
值代替我们得到
现在黄色更浓,但文字开始变浅。
对于这样的任务,我实际上更喜欢使用混合模式 Darken。这可以通过使用
来完成
state.BlendMode = new PdfName("Darken");
而不是 state.FillOpacity = .3f
。这导致
这个 IMO 看起来更好。
客户是怎么做到的
OP 评论了
Client have given a pdf. In that, they highlighted text, the highlighted text is displayed in browser
客户的PDF实际上使用了注释,就像他原始代码中的OP一样,但相比之下,客户的每个注释都包含一个外观流,而iText生成的高亮注释则没有。
提供外观是可选的,如果提供 none,PDF 查看器确实应该生成外观。不过,显然有许多 PDF 查看器依赖于 PDF 带来的外观。
顺便说一句,客户端PDF中的外观实际上使用了混合模式Multiply。对于底层的白色和黑色,Darken 和 Multiply 具有相同的结果。
使其与注释一起工作
在评论中,OP 想知道
Please one more doubt, if the user wrongly highlighted then how to remove yellow color(or change yellow to white)? i changed yellow to white but it's not working. 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);
but it's not working.
他尝试的问题是:
- 外观模板原点在注释区左下角,不在页面。因此,要为相关区域着色,矩形的左下角必须位于 (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 显示,作为注释,它们可以很容易地删除。
在使用 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 查看器中看到突出显示的文本,(次优)解决方法可能是在内容流 现有内容下方添加一个黄色矩形(假设现有内容不是不透明的)。
这在 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 and we add a yellow rectangle, with the file hello_highlighted.pdf 的文件作为结果。
请注意,如果您将黄色矩形添加到不透明的形状下(例如图像下),您将看不到它。在这种情况下,您可以在 现有内容之上添加一个透明矩形 。
更新:我的例子是用Java写的。开发人员将其移植到 C# 应该不是问题。这只是将一些小写字母变成大写字母的问题。例如。 stamper.GetUnderContent(1)
代替 stamper.getUnderContent(1)
,canvas.SaveState()
代替 canvas.saveState()
,依此类推。
首先...
为什么 OP 的(更新的)代码不起作用
其实有两个因素。
首先,OP的代码中有一个问题,要在他使用的路径中添加一个矩形
canvas.Rectangle(rect);
不幸的是,这不是他所期望的:Rectangle
class 有多个属性,不仅仅是矩形的坐标,关于选定边框、边框颜色和内部颜色的最重要信息,以及PdfContentByte.Rectangle(Rectangle)
根据这些属性绘制一个矩形。
不过,在手头的例子中,rect
仅用于传输矩形的坐标,因此这些附加属性都是 false
或 null
。因此,canvas.Rectangle(rect)
什么都不做!
OP 应该使用
canvas.Rectangle(rect.Left, rect.Bottom, rect.Width, rect.Height);
这里。
此外,@Bruno在他的回答中提到
Note that you won't see the yellow rectangle if you add it under an opaque shape (e.g. under an image).
不幸的是,这里就是这种情况:文档实际上是一个扫描文档,每一页都是一个页面填充图像,在其下方绘制了等效文本(可能在 OCR 之后)以允许文本复制和粘贴。
因此,无论 OP 的代码可能在 UnderContent
上绘制什么,它都将被该图像隐藏。
因此,让我们尝试一些不同的东西...
如何让它发挥作用
@Bruno 在他的回答中也指出了这种情况的解决方案:
In that case, you could add a transparent rectangle on top of the existing content.
我们根据这个建议替换
canvas = stamper.GetUnderContent(pageno);
来自
canvas = stamper.GetOverContent(pageno);
PdfGState state = new PdfGState();
state.FillOpacity = .3f;
canvas.SetGState(state);
在第三个文档页面上选择单词 "support" 我们得到:
这里的黄色很淡
使用 .6
的 Opacity
值代替我们得到
现在黄色更浓,但文字开始变浅。
对于这样的任务,我实际上更喜欢使用混合模式 Darken。这可以通过使用
来完成state.BlendMode = new PdfName("Darken");
而不是 state.FillOpacity = .3f
。这导致
这个 IMO 看起来更好。
客户是怎么做到的
OP 评论了
Client have given a pdf. In that, they highlighted text, the highlighted text is displayed in browser
客户的PDF实际上使用了注释,就像他原始代码中的OP一样,但相比之下,客户的每个注释都包含一个外观流,而iText生成的高亮注释则没有。
提供外观是可选的,如果提供 none,PDF 查看器确实应该生成外观。不过,显然有许多 PDF 查看器依赖于 PDF 带来的外观。
顺便说一句,客户端PDF中的外观实际上使用了混合模式Multiply。对于底层的白色和黑色,Darken 和 Multiply 具有相同的结果。
使其与注释一起工作
在评论中,OP 想知道
Please one more doubt, if the user wrongly highlighted then how to remove yellow color(or change yellow to white)? i changed yellow to white but it's not working. 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);
but it's not working.
他尝试的问题是:
- 外观模板原点在注释区左下角,不在页面。因此,要为相关区域着色,矩形的左下角必须位于 (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 显示,作为注释,它们可以很容易地删除。