如何在任何pdf文件中使我的水印文本不可选? [英] how to make my watermark text in any pdf file as non-selectable?

查看:206
本文介绍了如何在任何pdf文件中使我的水印文本不可选?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have done watermark text in pdf file using itextpdf, but when I copy the actual text of the pdf file it allows us to copy the watermark text too. Is there anyway that we can restrict our watermark text as Non-selectable?

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编写代码,它是空心水平的,但我是能够在这里复制水印文本:(
i想要使用PdfPatternPainter替换我的代码,如果可能的话,因为PdfPatternPainter继承了PdfContentByte的所有字段。

i have written code using PdfContentByte, it is hollow and horizontal, but i am able to copy the watermark text here :( i want to replace my code using PdfPatternPainter, if may be possible because PdfPatternPainter inherits all the Fields of PdfContentByte.

这里是使用PdfContentByte的代码:

here is code using 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澄清

In the comments to the original question, the OP clarified


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

the only things here needed is, whenever you will try to select entire text of pdf, the watermark text should not be selected. i just want to know is there any approach other then using png image file.

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

This sounds like using a pattern with text content might be just right for you. Here a proof-of-concept using iText:

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,这里不需要繁重的工作,这不是安全功能,一旦你知道它放在哪里就很容易找到。

The text from the pattern is not selectable in Adobe Reader. And @gwillie, no need for heavy lifting here, this is no security feature, the text is easy to find once you know where it's put.

请注意这些模式可以变幻无常对于文本的自由定位,您可能希望在固定形式的xobject中填充具有该模式的矩形(因此与模式图块对齐)并将该xobject放在任何您想要的位置。

Please be aware that patterns can be fickle. For free positioning of the text, you might want to fill a rectangle with that pattern in a fixed form xobject (thus being on edge with the pattern tiles) and put that xobject wherever you want.

很可能你会想要应用透明度,否则不会填充但只是用这个图案画家对字母进行细细描边:

And quite probably you will want to apply transparency or else not fill but only thinly stroke the letters like with this pattern painter:

    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的新详细代码考虑在内因为非复制和粘贴功能可能如下所示:

PS: Taking the OP's new detailed code into account a method adding that as non-copy&paste-able stuff may look like this:

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();
}

表示例如as

BTW,我将Helvetica Bold更改为非嵌入式,因为它是标准的14种字体之一。

BTW, I changed the Helvetica Bold to not-embedded as it is one of the standard 14 fonts.

PPS:在评论中,OP还想知道

PPS: In the comments the OP wondered furthermore


我们的水印文本是否有任何方式可以解决问题实际文本和Image的情况下它前进。我尝试过getUnderContent(),但是我们的Pdf图像隐藏了这个文本。

is there any way that our watermark text go backgroud of actual text and in case of Image it goes foreground. i have tried with getUnderContent() but our Pdf image Hide this text.

没有对页面内容进行排序(第一个图像,然后是水印,然后文本 - 一般不是微不足道的)一个人可以尝试用图像收集所有区域(使用iText解析器包类),然后将水印放到undercontent,并且overcontent也放水印但是仅在您找到图像的组合区域中。更容易实现,但有点脏。例如

Short of sorting the page contents (first images, then the water mark, then the text - not trivial in general) one can try and collect all the areas with images (using the iText parser package classes), then put the water mark to the undercontent, and to the overcontent also put the water mark but only in the combined regions in which you found images. Much easier to implement but a bit dirty. E.g.

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<Vector> 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<Vector> positive = Arrays.asList(A, B, C, D);
static List<Vector> negative = Arrays.asList(A, D, C, B);

List<Vector> getImageBordersPathPoints(PdfReader reader, int page) throws IOException
{
    final List<Vector> result = new ArrayList<Vector>();
    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<Vector> 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;
}

Vector com.itextpdf.text.pdf.parser.Vector

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

The result (the Dexx logo is an image, the address is text):

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

Unfortunately, though, the parsing API does not yet signal vector graphics. Thus, vector graphics (e.g. colored backgrounds which essentially are filled rectangles drawn using vector graphics operations) cover the water mark.

这篇关于如何在任何pdf文件中使我的水印文本不可选?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆