Я пытаюсь сделать несъемный прозрачный водяной знак в 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();
}
}
}
Как сделать так, чтобы водяной знак не закрывал текст?




Мне удалось выполнить это требование, сделав непрозрачность 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, что является достаточно прозрачным.