Невозможно сделать несъемный водяной знак прозрачным в Itext5

Я пытаюсь сделать несъемный прозрачный водяной знак в Itext5. Мне удалось сделать водяной знак неустранимым с помощью PdfPatternPainter, но все еще сталкиваюсь с проблемой, заключающейся в том, что водяной знак не очень прозрачен и все еще закрывает содержимое, что затрудняет его чтение. .

Мой код выглядит следующим образом:

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

Как сделать так, чтобы водяной знак не закрывал текст?

Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
0
0
76
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Мне удалось выполнить это требование, сделав непрозрачность overContent очень низкой следующим образом:

state.setFillOpacity(0.01f);

а также измените цвет художника на:

BaseColor baseColor = new BaseColor(10, 10, 10);
Ответ принят как подходящий

Как стало ясно при обсуждении вашего дополнительного вопроса, причина, по которой водяной знак не очень прозрачен и все еще закрывает контент и затрудняет его чтение с исходной непрозрачностью 0,1, заключается в том, что вы применяете водяной знак много раз. , много раз, в моем примере документа 35 раз на страницу! Это приводит к существенному увеличению эффективной непрозрачности.

Вы делаете это, потому что у вас есть код, применяющий водяной знак в вашем двойном цикле:

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

Чтобы применить его только один раз, переместите код применения из этого цикла:

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

При применении 35 раз с индивидуальной непрозрачностью 0,1 эффективная непрозрачность вашего водяного знака стала примерно 0,975, то есть фактически непрозрачной.

При применении 35 раз с индивидуальной непрозрачностью 0,01, значением, которое вы указали в своем ответе, эффективная непрозрачность вашего водяного знака стала примерно 0,3, что является достаточно прозрачным.

Другие вопросы по теме