iText 为选定页面添加水印
iText add Watermark to selected pages
我需要为每个包含特定文本的页面添加水印,例如"PROCEDURE DELETED"。
根据 Bruno Lowagie 在 Adding watermark directly to the stream
中的建议
到目前为止,PdfWatermark Class 具有:
protected Phrase watermark = new Phrase("DELETED", new Font(FontFamily.HELVETICA, 60, Font.NORMAL, BaseColor.PINK));
ArrayList<Integer> arrPages = new ArrayList<Integer>();
boolean pdfChecked = false;
@Override
public void onEndPage(PdfWriter writer, Document document) {
if(pdfChecked == false) {
detectPages(writer, document);
pdfChecked = true;
}
int pageNum = writer.getPageNumber();
if(arrPages.contains(pageNum)) {
PdfContentByte canvas = writer.getDirectContentUnder();
ColumnText.showTextAligned(canvas, Element.ALIGN_CENTER, watermark, 298, 421, 45);
}
}
如果我在我的自定义 detectPages 方法中将数字 3 添加到 arrPages ArrayList,则效果很好 - 它在第 3 页上显示所需的水印。
我遇到的问题是如何在文档中搜索我有权访问的文本字符串,只能从 PdfWriter 编写器或发送到 onEndPage 方法的 com.itextpdf.text.Document 文档中搜索。
这是我尝试过的,但没有成功:
private void detectPages(PdfWriter writer, Document document) {
try {
//arrPages.add(3);
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
PdfWriter.getInstance(document, byteArrayOutputStream);
//following code no work
PdfReader reader = new PdfReader(writer.getDirectContent().getPdfDocument());
PdfContentByte canvas = writer.getDirectContent();
PdfImportedPage page;
for (int i = 0; i < reader.getNumberOfPages(); ) {
page = writer.getImportedPage(reader, ++i);
canvas.addTemplate(page, 1f, 0, 0.4f, 0.4f, 72, 50 * i);
canvas.beginText();
canvas.showTextAligned(Element.ALIGN_CENTER,
//search String
String.valueOf((char)(181 + i)), 496, 150 + 50 * i, 0);
//if(detected) arrPages.add(i);
canvas.endText();
}
我是否在正确的轨道上将此作为解决方案,还是我需要退出?
任何人都可以提供扫描文档并挑选 "PROCEDURE DELETED" 页所需的缺失 link 吗?
编辑:我正在使用 iText 5.0.4 - 目前无法升级到 5。5.X,但可能会升级到低于该版本的最新版本。
EDIT2:更多信息:这是向文档添加文本的方法 (doc
):
String processed = processText(template);
List<Element> objects = HTMLWorker.parseToListLog(new StringReader(processed),
styles, interfaceProps, errors);
for (Element elem : objects) {
doc.add(elem);
}
这是在我控制的 addText
方法中调用的。 template
只是来自数据库 LOB 的 html。 processText
检查 html 是否包含卷曲的自定义标记,如 ${replaceMe}
.
这似乎是在生成文档期间识别 "PROCEDURE DELETED" 字符串的地方,但我没有看到 Chunk.setGenericTags() 的路径。
EDIT3:Table 困难
List<Element> objects = HTMLWorker.parseToListLog(new StringReader(processed),
styles, interfaceProps, errors);
for (Element elem : objects) {
//Code below no work
if (elem instanceof PdfPTable) {
PdfPTable table = (PdfPTable) elem;
ArrayList<Chunk> chks = table.getChunks();
for(Chunk chk : chks){
if(chk.toString().contains("TEST DELETED")) {
chk.setGenericTag("delete_tag");
}
}
}
doc.add(elem);
}
评论者 mlk 和 Bruno 建议在将 "PROCEDURE DELETED" 关键字添加到文档时检测它们。但是,由于关键字必须在 table 内,因此必须通过 PdfPTable 而不是更简单的 Element 来检测它们。
我用上面的代码做不到。关于如何在 table 单元格中查找文本并对其进行字符串比较,有什么建议吗?
EDIT4:基于一些实验,我想做一些断言,请告诉我如何通过它们:
- 需要使用
Chunk.setGenericTag()
来触发处理程序 onGenericTag
- 出于某种原因
(PdfPTable) table.getChunks()
没有 return 块,至少我的系统可以接受。这是违反直觉的,可能存在导致此行为的设置、版本或代码错误。
- 因此,table 中的选择文本字符串不能用于触发水印。
感谢@mkl 和@Bruno 的帮助,我终于得到了一个可行的解决方案。欢迎任何有兴趣的人提供更优雅的方法 - 当然有空间。
两个 类 在原始问题中给出的所有片段中都在起作用。以下是体现工作解决方案的部分代码。
public class PdfExporter
//a custom class to build content
//create some content to add to pdf
String text = "<div>Lots of important content here</div>";
//assume the section is known to be deleted
if(section_deleted) {
//add a special marker to the text, in white-on-white
text = "<span style=\"color:white;\">.!^DEL^?.</span>" + text + "</span>";
}
//based on some indicator, we know we want to force a new page for a new section
boolean ensureNewPage = true;
//use an instance of PdfDocHandler to add the content
pdfDocHandler.addText(text, ensureNewPage);
public class PdfDocHandler extends PdfPageEventHelper
private boolean isDEL;
public boolean addText(String text, boolean ensureNewPage)
if (ensureNewPage) {
//turn isDEL off: a forced pagebreak indicates a new section
isDEL = false;
}
//attempt to find the special DELETE marker in first chunk
//NOTE: this can be done several ways
ArrayList<Chunk> chks = elem.getChunks();
if(chks.size()>0) {
if(chks.get(0).getContent().contains(".!^DEL^?.")) {
//special delete marker found in text
isDEL = true;
}
}
//doc is an iText Document
doc.add(elem);
public void onEndPage(PdfWriter writer, Document document) {
if(isDEL) {
//set the watermark
Phrase watermark = new Phrase("DELETED", new Font(Font.FontFamily.HELVETICA, 60, Font.NORMAL, BaseColor.PINK));
PdfContentByte canvas = writer.getDirectContentUnder();
ColumnText.showTextAligned(canvas, Element.ALIGN_CENTER, watermark, 298, 421, 45);
}
}
我需要为每个包含特定文本的页面添加水印,例如"PROCEDURE DELETED"。
根据 Bruno Lowagie 在 Adding watermark directly to the stream
中的建议到目前为止,PdfWatermark Class 具有:
protected Phrase watermark = new Phrase("DELETED", new Font(FontFamily.HELVETICA, 60, Font.NORMAL, BaseColor.PINK));
ArrayList<Integer> arrPages = new ArrayList<Integer>();
boolean pdfChecked = false;
@Override
public void onEndPage(PdfWriter writer, Document document) {
if(pdfChecked == false) {
detectPages(writer, document);
pdfChecked = true;
}
int pageNum = writer.getPageNumber();
if(arrPages.contains(pageNum)) {
PdfContentByte canvas = writer.getDirectContentUnder();
ColumnText.showTextAligned(canvas, Element.ALIGN_CENTER, watermark, 298, 421, 45);
}
}
如果我在我的自定义 detectPages 方法中将数字 3 添加到 arrPages ArrayList,则效果很好 - 它在第 3 页上显示所需的水印。
我遇到的问题是如何在文档中搜索我有权访问的文本字符串,只能从 PdfWriter 编写器或发送到 onEndPage 方法的 com.itextpdf.text.Document 文档中搜索。
这是我尝试过的,但没有成功:
private void detectPages(PdfWriter writer, Document document) {
try {
//arrPages.add(3);
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
PdfWriter.getInstance(document, byteArrayOutputStream);
//following code no work
PdfReader reader = new PdfReader(writer.getDirectContent().getPdfDocument());
PdfContentByte canvas = writer.getDirectContent();
PdfImportedPage page;
for (int i = 0; i < reader.getNumberOfPages(); ) {
page = writer.getImportedPage(reader, ++i);
canvas.addTemplate(page, 1f, 0, 0.4f, 0.4f, 72, 50 * i);
canvas.beginText();
canvas.showTextAligned(Element.ALIGN_CENTER,
//search String
String.valueOf((char)(181 + i)), 496, 150 + 50 * i, 0);
//if(detected) arrPages.add(i);
canvas.endText();
}
我是否在正确的轨道上将此作为解决方案,还是我需要退出?
任何人都可以提供扫描文档并挑选 "PROCEDURE DELETED" 页所需的缺失 link 吗?
编辑:我正在使用 iText 5.0.4 - 目前无法升级到 5。5.X,但可能会升级到低于该版本的最新版本。
EDIT2:更多信息:这是向文档添加文本的方法 (doc
):
String processed = processText(template);
List<Element> objects = HTMLWorker.parseToListLog(new StringReader(processed),
styles, interfaceProps, errors);
for (Element elem : objects) {
doc.add(elem);
}
这是在我控制的 addText
方法中调用的。 template
只是来自数据库 LOB 的 html。 processText
检查 html 是否包含卷曲的自定义标记,如 ${replaceMe}
.
这似乎是在生成文档期间识别 "PROCEDURE DELETED" 字符串的地方,但我没有看到 Chunk.setGenericTags() 的路径。
EDIT3:Table 困难
List<Element> objects = HTMLWorker.parseToListLog(new StringReader(processed),
styles, interfaceProps, errors);
for (Element elem : objects) {
//Code below no work
if (elem instanceof PdfPTable) {
PdfPTable table = (PdfPTable) elem;
ArrayList<Chunk> chks = table.getChunks();
for(Chunk chk : chks){
if(chk.toString().contains("TEST DELETED")) {
chk.setGenericTag("delete_tag");
}
}
}
doc.add(elem);
}
评论者 mlk 和 Bruno 建议在将 "PROCEDURE DELETED" 关键字添加到文档时检测它们。但是,由于关键字必须在 table 内,因此必须通过 PdfPTable 而不是更简单的 Element 来检测它们。
我用上面的代码做不到。关于如何在 table 单元格中查找文本并对其进行字符串比较,有什么建议吗?
EDIT4:基于一些实验,我想做一些断言,请告诉我如何通过它们:
- 需要使用
Chunk.setGenericTag()
来触发处理程序onGenericTag
- 出于某种原因
(PdfPTable) table.getChunks()
没有 return 块,至少我的系统可以接受。这是违反直觉的,可能存在导致此行为的设置、版本或代码错误。 - 因此,table 中的选择文本字符串不能用于触发水印。
感谢@mkl 和@Bruno 的帮助,我终于得到了一个可行的解决方案。欢迎任何有兴趣的人提供更优雅的方法 - 当然有空间。
两个 类 在原始问题中给出的所有片段中都在起作用。以下是体现工作解决方案的部分代码。
public class PdfExporter
//a custom class to build content
//create some content to add to pdf
String text = "<div>Lots of important content here</div>";
//assume the section is known to be deleted
if(section_deleted) {
//add a special marker to the text, in white-on-white
text = "<span style=\"color:white;\">.!^DEL^?.</span>" + text + "</span>";
}
//based on some indicator, we know we want to force a new page for a new section
boolean ensureNewPage = true;
//use an instance of PdfDocHandler to add the content
pdfDocHandler.addText(text, ensureNewPage);
public class PdfDocHandler extends PdfPageEventHelper
private boolean isDEL;
public boolean addText(String text, boolean ensureNewPage)
if (ensureNewPage) {
//turn isDEL off: a forced pagebreak indicates a new section
isDEL = false;
}
//attempt to find the special DELETE marker in first chunk
//NOTE: this can be done several ways
ArrayList<Chunk> chks = elem.getChunks();
if(chks.size()>0) {
if(chks.get(0).getContent().contains(".!^DEL^?.")) {
//special delete marker found in text
isDEL = true;
}
}
//doc is an iText Document
doc.add(elem);
public void onEndPage(PdfWriter writer, Document document) {
if(isDEL) {
//set the watermark
Phrase watermark = new Phrase("DELETED", new Font(Font.FontFamily.HELVETICA, 60, Font.NORMAL, BaseColor.PINK));
PdfContentByte canvas = writer.getDirectContentUnder();
ColumnText.showTextAligned(canvas, Element.ALIGN_CENTER, watermark, 298, 421, 45);
}
}