如何在任何pdf文件中使我的水印文本不可选?

我使用itextpdf在pdf文件中完成了水印文本,但是当我复制pdf文件的实际文本时,它允许我们复制水印文本。 反正我们可以将水印文本限制为不可选择吗?

Image watermark_image = Image.getInstance(imageFile.getAbsolutePath()); while (i < num_of_pages) { i++; //To pass our watermark over text add_waterMark = pdfStamper.getOverContent(i); //To pass our watermark under text //add_waterMark = pdfStamper.getUnderContent(i); // watermark_image. watermark_image.setAbsolutePosition(0, 0); add_waterMark.beginText(); //add_waterMark.setTextRenderingMode(number_of_pages); //watermark_image is png file add_waterMark.addImage(watermark_image); add_waterMark.endText(); } 

我使用PdfContentByte编写代码,它是空心水平的,但我可以在这里复制水印文本:(我想用PdfPatternPainter替换我的代码,如果可能的话,因为PdfPatternPainterinheritance了PdfContentByte的所有字段。

这是使用PdfContentByte的代码:

 int n = reader.getNumberOfPages(); PdfContentByte under; PdfGState gstate = new PdfGState(); gstate.setFillOpacity(0.35f); gstate.setStrokeOpacity(0.35f); BaseFont font = BaseFont.createFont(BaseFont.HELVETICA_BOLD, BaseFont.WINANSI, BaseFont.EMBEDDED); Rectangle size = reader.getPageSizeWithRotation(1); // float angle = (float) ((180 * (Math.asin(size.getHeight() // / Math.sqrt(size.getWidth() * size.getWidth() // + size.getHeight() * size.getHeight())))) / Math.PI); int i = 1; while (i < n + 1) { under = stamper.getOverContent(i); under.setColorStroke(new BaseColor(192, 192, 192)); i++; under.beginText(); under.setTextRenderingMode(PdfContentByte.TEXT_RENDER_MODE_STROKE); under.setLineWidth(0.85f); under.setLineDash(0.4f, 0.4f, 0.2f); under.showTextAlignedKerned(Element.ALIGN_MIDDLE, "user name must required", 250, 780, MYConstants.WATERMARK_PAGE_ANGLE); under.setFontAndSize(font, 42); under.showTextAlignedKerned(Element.ALIGN_MIDDLE, "user Company name required", 200, 730, MyConstants.WATERMARK_PAGE_ANGLE); under.setFontAndSize(font, 42); under.showTextAlignedKerned(Element.ALIGN_MIDDLE, "Plesae enter your email id", 150, 680, MyConstants.WATERMARK_PAGE_ANGLE); under.endText(); } stamper.close(); } 

在对原始问题的评论中,OP澄清了

这里唯一需要的是,每当您尝试选择pdf的整个文本时,都不应选择水印文本。 我只是想知道除了使用png图像文件之外还有其他任何方法。

这听起来像使用带有文本内容的模式可能适合您。 这是使用iText的概念validation:

 void addTextPatternToOverContent(File source, File target) throws IOException, DocumentException { PdfReader reader = new PdfReader(source.getPath()); OutputStream os = new FileOutputStream(target); PdfStamper stamper = new PdfStamper(reader, os); PdfPatternPainter painter = stamper.getOverContent(1).createPattern(200, 150); painter.setColorFill(BaseColor.BLACK); painter.beginText(); painter.setTextMatrix(AffineTransform.getTranslateInstance(0, 50)); painter.setFontAndSize(BaseFont.createFont(), 100); painter.showText("Test"); painter.endText(); for (int i = reader.getNumberOfPages(); i > 0; i--) { PdfContentByte overContent = stamper.getOverContent(i); overContent.setColorFill(new PatternColor(painter)); overContent.rectangle(200, 300, 200, 150); overContent.fill(); } stamper.close(); os.close(); reader.close(); } 

在Adobe Reader中无法选择模式中的文本。 而@gwillie,这里不需要繁重的工作,这不是安全function,一旦你知道它放在哪里就很容易找到。

请注意,模式可能是善变的。 对于文本的自由定位,您可能希望在固定forms的xobject中填充具有该模式的矩形(因此与图案切片一起使用)并将该xobject放在任何您想要的位置。

很可能你会想要应用透明度,或者不填充,但只是用这个图案画家的字母划线:

  PdfPatternPainter painter = stamper.getOverContent(1).createPattern(200, 150); painter.setColorStroke(BaseColor.BLACK); painter.beginText(); painter.setTextRenderingMode(PdfPatternPainter.TEXT_RENDER_MODE_STROKE); painter.setTextMatrix(AffineTransform.getTranslateInstance(0, 50)); painter.setFontAndSize(BaseFont.createFont(), 100); painter.showText("Test"); painter.endText(); 

PS:将OP的新详细代码考虑在内,添加一个方法,因为非复制和粘贴function可能如下所示:

 void addUserPatternToOverContent(File source, File target) throws IOException, DocumentException { PdfReader reader = new PdfReader(source.getPath()); OutputStream os = new FileOutputStream(target); PdfStamper stamper = new PdfStamper(reader, os); Rectangle pageSize = reader.getPageSize(1); final float WATERMARK_PAGE_ANGLE = -72; BaseFont font = BaseFont.createFont(BaseFont.HELVETICA_BOLD, BaseFont.WINANSI, BaseFont.NOT_EMBEDDED); PdfPatternPainter painter = stamper.getOverContent(1).createPattern(pageSize.getWidth(), pageSize.getHeight()); painter.setColorStroke(new BaseColor(192, 192, 192)); painter.setLineWidth(0.85f); painter.setLineDash(0.4f, 0.4f, 0.2f); painter.beginText(); painter.setTextRenderingMode(PdfPatternPainter.TEXT_RENDER_MODE_STROKE); painter.setFontAndSize(font, 42); painter.showTextAlignedKerned(Element.ALIGN_MIDDLE, "user name must required", 250, 780, WATERMARK_PAGE_ANGLE); painter.showTextAlignedKerned(Element.ALIGN_MIDDLE, "user Company name required", 200, 730, WATERMARK_PAGE_ANGLE); painter.showTextAlignedKerned(Element.ALIGN_MIDDLE, "Plesae enter your email id", 150, 680, WATERMARK_PAGE_ANGLE); painter.endText(); for (int i = reader.getNumberOfPages(); i > 0; i--) { Rectangle thisPageSize = reader.getPageSize(i); PdfContentByte overContent = stamper.getOverContent(i); overContent.setColorFill(new PatternColor(painter)); overContent.rectangle(thisPageSize.getLeft(), thisPageSize.getBottom(), thisPageSize.getWidth(), thisPageSize.getHeight()); overContent.fill(); } stamper.close(); os.close(); reader.close(); } 

这显示例如

水标志应用于样本页面

顺便说一句,我将Helvetica Bold更改为未嵌入,因为它是标准的14种字体之一。

PPS: OP在评论中进一步提出了疑问

是否有任何方式我们的水印文本去实际文本的背景和在图像的情况下它前进。 我尝试过getUnderContent()但我们的Pdf图像隐藏此文本。

如果没有对页面内容进行排序(第一个图像,然后是水印,那么文本 – 一般不是微不足道),可以尝试用图像收集所有区域(使用iText解析器包类),然后将水印放到不足之处,以及过度的内容也只是在你找到图像的组合区域中放置了水印。 更容易实现,但有点脏。 例如

 void addUserPatternOverAndUnder(File source, File target) throws IOException, DocumentException { PdfReader reader = new PdfReader(source.getPath()); OutputStream os = new FileOutputStream(target); PdfStamper stamper = new PdfStamper(reader, os); Rectangle pageSize = reader.getPageSize(1); final float WATERMARK_PAGE_ANGLE = -60; BaseFont font = BaseFont.createFont(BaseFont.HELVETICA_BOLD, BaseFont.WINANSI, BaseFont.NOT_EMBEDDED); PdfPatternPainter painter = stamper.getOverContent(1).createPattern(pageSize.getWidth(), pageSize.getHeight()); painter.setColorStroke(new BaseColor(0, 192, 192)); painter.setLineWidth(0.85f); painter.setLineDash(0.4f, 0.4f, 0.2f); painter.beginText(); painter.setTextRenderingMode(PdfPatternPainter.TEXT_RENDER_MODE_STROKE); painter.setFontAndSize(font, 42); painter.showTextAlignedKerned(Element.ALIGN_MIDDLE, "user name must required", 150, 780, WATERMARK_PAGE_ANGLE); painter.showTextAlignedKerned(Element.ALIGN_MIDDLE, "user Company name required", 100, 730, WATERMARK_PAGE_ANGLE); painter.showTextAlignedKerned(Element.ALIGN_MIDDLE, "Plesae enter your email id", 050, 680, WATERMARK_PAGE_ANGLE); painter.endText(); for (int i = reader.getNumberOfPages(); i > 0; i--) { Rectangle thisPageSize = reader.getPageSize(i); PdfContentByte underContent = stamper.getUnderContent(i); underContent.setColorFill(new PatternColor(painter)); underContent.rectangle(thisPageSize.getLeft(), thisPageSize.getBottom(), thisPageSize.getWidth(), thisPageSize.getHeight()); underContent.fill(); List path = getImageBordersPathPoints(reader, i); if (path != null && !path.isEmpty()) { PdfContentByte overContent = stamper.getOverContent(i); overContent.setColorFill(new PatternColor(painter)); for (int index = 0; index < path.size(); index++) { Vector corner = path.get(index); if (index % 4 == 0) { overContent.moveTo(corner.get(Vector.I1), corner.get(Vector.I2)); } else { overContent.lineTo(corner.get(Vector.I1), corner.get(Vector.I2)); if (index % 4 == 3) { overContent.closePath(); } } } overContent.fill(); } } stamper.close(); os.close(); reader.close(); } static Vector A = new Vector(0, 0, 1); static Vector B = new Vector(1, 0, 1); static Vector C = new Vector(1, 1, 1); static Vector D = new Vector(0, 1, 1); static List positive = Arrays.asList(A, B, C, D); static List negative = Arrays.asList(A, D, C, B); List getImageBordersPathPoints(PdfReader reader, int page) throws IOException { final List result = new ArrayList(); RenderListener listener = new RenderListener() { public void renderText(TextRenderInfo renderInfo) { } public void endTextBlock() { } public void beginTextBlock() { } public void renderImage(ImageRenderInfo renderInfo) { Matrix ctm = renderInfo.getImageCTM(); List unitCorners = ctm.getDeterminant() > 0 ? positive : negative; for (Vector corner : unitCorners) { result.add(corner.cross(ctm)); } } }; PdfReaderContentParser parser = new PdfReaderContentParser(reader); parser.processContent(page, listener); return result; } 

Vectorcom.itextpdf.text.pdf.parser.Vector

结果(Dexx徽标是图像,地址是文本):

水标志以新的方式应用于样本页面

不幸的是,解析API还没有发出矢量图形信号。 因此,矢量图形(例如,基本上是使用矢量图形操作绘制的填充矩形的彩色背景 )覆盖水印。