Search code examples
javaitextwatermarkitext5

Unable to make the non removable watermark transparent in Itext5


I am trying to make non removable transparent watermark in Itext5, I was able to make the watermark non removable using the PdfPatternPainter,but still facing an issue that the watermark is not transparent much and it is still covering the content and makes it harder to read.

My code is as follows:

public class TestWatermark {

    public static String resourcesPath = "C:\\Users\\java\\Desktop\\TestWaterMark\\";
    public static String FILE_NAME = resourcesPath + "test.pdf";

    public static void main(String[] args) throws IOException {
        System.out.println("########## STARTED ADDING WATERMARK ###########");
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        try {
            byte[] byteArray = Files.readAllBytes(Paths.get(FILE_NAME));
            String watermarkText = "confidential";
            String fontPath = resourcesPath + "myCustomFont.ttf";
            Font arabicFont = FontFactory.getFont(fontPath, BaseFont.IDENTITY_H, 16);

            BaseFont baseFont = arabicFont.getBaseFont();
            PdfReader reader = new PdfReader(byteArray);
            PdfStamper stamper = new PdfStamper(reader, baos);

            int numberOfPages = reader.getNumberOfPages();

            float height = baseFont.getAscentPoint(watermarkText, 24) + baseFont.getDescentPoint(watermarkText, 24);

            for (int i = 1; i <= numberOfPages; i++) {

                Rectangle pageSize = reader.getPageSizeWithRotation(i);
                PdfContentByte overContent = stamper.getOverContent(i);

                PdfPatternPainter bodyPainter = stamper.getOverContent(i).createPattern(pageSize.getWidth(),
                        pageSize.getHeight());
                BaseColor baseColor = new BaseColor(10, 10, 10);
                bodyPainter.setColorStroke(baseColor);
                bodyPainter.setColorFill(baseColor);
                bodyPainter.setLineWidth(0.85f);
                bodyPainter.setLineDash(0.2f, 0.2f, 0.2f);

                PdfGState state = new PdfGState();
                state.setFillOpacity(0.01f);
                overContent.saveState();
                overContent.setGState(state);

                for (float x = 70f; x < pageSize.getWidth(); x += height + 100) {
                    for (float y = 90; y < pageSize.getHeight(); y += height + 100) {

                        bodyPainter.beginText();
                        bodyPainter.setTextRenderingMode(PdfPatternPainter.TEXT_RENDER_MODE_FILL);
                        bodyPainter.setFontAndSize(baseFont, 13);
                        bodyPainter.showTextAlignedKerned(Element.ALIGN_MIDDLE, watermarkText, x, y, 45f);
                        bodyPainter.endText();

                        overContent.setColorFill(new PatternColor(bodyPainter));
                        overContent.rectangle(pageSize.getLeft(), pageSize.getBottom(), pageSize.getWidth(),
                                pageSize.getHeight());
                        overContent.fill();

                    }
                }

                overContent.restoreState();

            }

            stamper.close();
            reader.close();
            byteArray = baos.toByteArray();
            File outputFile = new File(resourcesPath + "output.pdf");
            if (outputFile.exists()) {
                outputFile.delete();
            }
            Files.write(outputFile.toPath(), byteArray);

            System.out.println("########## FINISHED ADDING WATERMARK ###########");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

How can I make my watermark not cover the text?


Solution

  • As became clear while discussing your follow-up question, the reason why the watermark is not transparent much and it is still covering the content and makes it harder to read with the original opacity of 0.1, is that you apply the watermark many, many times, in my example document 35 times per page! That makes the effective opacity rise substantially.

    You do so because you have the code applying the watermark in your double loop:

    for (float x = 70f; x < pageSize.getWidth(); x += height + 100) {
        for (float y = 90; y < pageSize.getHeight(); y += height + 100) {
            bodyPainter.beginText();
            bodyPainter.setTextRenderingMode(PdfPatternPainter.TEXT_RENDER_MODE_FILL);
            bodyPainter.setFontAndSize(baseFont, 13);
            bodyPainter.showTextAlignedKerned(Element.ALIGN_MIDDLE, watermarkText, x, y, 45f);
            bodyPainter.endText();
    
            overContent.setColorFill(new PatternColor(bodyPainter));
            overContent.rectangle(pageSize.getLeft(), pageSize.getBottom(), pageSize.getWidth(),
                    pageSize.getHeight());
            overContent.fill();
        }
    }
    

    To apply it only once, move the applying code out of that loop:

    for (float x = 70f; x < pageSize.getWidth(); x += height + 100) {
        for (float y = 90; y < pageSize.getHeight(); y += height + 100) {
            bodyPainter.beginText();
            bodyPainter.setTextRenderingMode(PdfPatternPainter.TEXT_RENDER_MODE_FILL);
            bodyPainter.setFontAndSize(baseFont, 13);
            bodyPainter.showTextAlignedKerned(Element.ALIGN_MIDDLE, watermarkText, x, y, 45f);
            bodyPainter.endText();
        }
    }
    
    overContent.setColorFill(new PatternColor(bodyPainter));
    overContent.rectangle(pageSize.getLeft(), pageSize.getBottom(), pageSize.getWidth(),
            pageSize.getHeight());
    overContent.fill();
    

    Applied 35 times with an individual opacity of 0.1, the effective opacity of your watermark became some 0.975, effectively opaque.

    Applied 35 times with an individual opacity of 0.01, the value you mention in your answer, the effective opacity of your watermark became some 0.3, fairly transparent.