提供一个pdf水印生成工具类
public class PdfWaterMarkUtil {
private PdfWaterMarkUtil() {
}
private static final float LEN_OFFSET = 100;
private static final float TILE_MALPOSITION = 0.3f;
public static final int TILE = 0;
public static final int TOP_LEFT = 1;
public static final int TOP_CENTER = 2;
public static final int TOP_RIGHT = 3;
public static final int CENTER_LEFT = 4;
public static final int CENTER = 5;
public static final int CENTER_RIGHT = 6;
public static final int BOTTOM_LEFT = 7;
public static final int BOTTOM_CENTER = 8;
public static final int BOTTOM_RIGHT = 9;
private static final Map<String, BaseFont> FONT_MAP = new HashMap<>();
private static final Map<Integer, PdfGState> GS_MAP = new HashMap<>();
private static final float LEN_TO_PX = 28.347618466331845f;
public static void addWaterMark(String srcPdfFile, OutputStream out, List<MarkInfo> markInfoList) throws Exception {
addWaterMark(new PdfReader(srcPdfFile), out, markInfoList);
}
public static void addWaterMark(File pdfFile, OutputStream out, List<MarkInfo> markInfoList) throws Exception {
addWaterMark(new PdfReader(new FileInputStream(pdfFile)), out, markInfoList);
}
public static void addWaterMark(URL pdfUrl, OutputStream out, List<MarkInfo> markInfoList) throws Exception {
addWaterMark(new PdfReader(pdfUrl), out, markInfoList);
}
private static void addWaterMark(PdfReader reader, OutputStream out, List<MarkInfo> markInfoList) throws Exception {
PdfStamper pdfStamper = new PdfStamper(reader, out);
int pageNumber = reader.getNumberOfPages() + 1;
for (int i = 1; i < pageNumber; i++) {
Rectangle pageSize = reader.getPageSize(i);
float height = pageSize.getHeight();
float width = pageSize.getWidth();
PdfContentByte content = pdfStamper.getOverContent(i);
content.beginText();
for (MarkInfo markInfo : markInfoList) {
content.setGState(getPdfGState(markInfo.getPellucidity()));
content.setFontAndSize(getFont(markInfo.getFontFamily()), markInfo.getFontSize());
content.setColorFill(Color.get(markInfo.getFontColor()));
switch (markInfo.getPositionType()) {
case TILE:
tile(markInfo, height, width, content);
break;
case TOP_LEFT:
topLeft(markInfo, height, width, content);
break;
case TOP_CENTER:
topCenter(markInfo, height, width, content);
break;
case TOP_RIGHT:
topRight(markInfo, height, width, content);
break;
case CENTER_LEFT:
centerLeft(markInfo, height, width, content);
break;
case CENTER:
center(markInfo, height, width, content);
break;
case CENTER_RIGHT:
centerRight(markInfo, height, width, content);
break;
case BOTTOM_LEFT:
bottomLeft(markInfo, height, width, content);
break;
case BOTTOM_CENTER:
bottomCenter(markInfo, height, width, content);
break;
case BOTTOM_RIGHT:
bottomRight(markInfo, height, width, content);
break;
default:
}
}
content.endText();
}
pdfStamper.close();
}
private static PdfGState getPdfGState(int pellucidity) {
PdfGState gs = GS_MAP.get(pellucidity);
if (gs == null) {
gs = new PdfGState();
gs.setFillOpacity((100 - pellucidity) / 100f);
GS_MAP.put(pellucidity, gs);
}
return gs;
}
private static void bottomRight(MarkInfo markInfo, float height, float width, PdfContentByte content) {
final String markText = markInfo.getMarkText();
final float rotation = markInfo.getRotation();
float x = getRightX(markInfo, width, content);
float y = getBottomY(markInfo, height, content);
content.showTextAligned(Element.ALIGN_LEFT, markText, x, y, rotation);
}
private static void bottomCenter(MarkInfo markInfo, float height, float width, PdfContentByte content) {
final String markText = markInfo.getMarkText();
final float rotation = markInfo.getRotation();
float x = getCenterX(markInfo, width, content);
float y = getBottomY(markInfo, height, content);
content.showTextAligned(Element.ALIGN_LEFT, markText, x, y, rotation);
}
private static void bottomLeft(MarkInfo markInfo, float height, float width, PdfContentByte content) {
final String markText = markInfo.getMarkText();
final float rotation = markInfo.getRotation();
float x = getLeftX(markInfo, width, content);
float y = getBottomY(markInfo, height, content);
content.showTextAligned(Element.ALIGN_LEFT, markText, x, y, rotation);
}
private static void centerRight(MarkInfo markInfo, float height, float width, PdfContentByte content) {
final String markText = markInfo.getMarkText();
final float rotation = markInfo.getRotation();
float x = getRightX(markInfo, width, content);
float y = getCenterY(markInfo, height, content);
content.showTextAligned(Element.ALIGN_LEFT, markText, x, y, rotation);
}
private static void centerLeft(MarkInfo markInfo, float height, float width, PdfContentByte content) {
final String markText = markInfo.getMarkText();
final float rotation = markInfo.getRotation();
float x = getLeftX(markInfo, width, content);
float y = getCenterY(markInfo, height, content);
content.showTextAligned(Element.ALIGN_LEFT, markText, x, y, rotation);
}
private static void topRight(MarkInfo markInfo, float height, float width, PdfContentByte content) {
final String markText = markInfo.getMarkText();
final float rotation = markInfo.getRotation();
float x = getRightX(markInfo, width, content);
float y = getTopY(markInfo, height, content);
content.showTextAligned(Element.ALIGN_LEFT, markText, x, y, rotation);
}
private static void topCenter(MarkInfo markInfo, float height, float width, PdfContentByte content) {
final String markText = markInfo.getMarkText();
final float rotation = markInfo.getRotation();
float x = getCenterX(markInfo, width, content);
float y = getTopY(markInfo, height, content);
content.showTextAligned(Element.ALIGN_LEFT, markText, x, y, rotation);
}
private static void topLeft(MarkInfo markInfo, float height, float width, PdfContentByte content) {
final String markText = markInfo.getMarkText();
final float rotation = markInfo.getRotation();
float x = getLeftX(markInfo, width, content);
float y = getTopY(markInfo, height, content);
content.showTextAligned(Element.ALIGN_LEFT, markText, x, y, rotation);
}
private static void center(MarkInfo markInfo, float height, float width, PdfContentByte content) {
final String markText = markInfo.getMarkText();
final float rotation = markInfo.getRotation();
float x = getCenterX(markInfo, width, content);
float y = getCenterY(markInfo, height, content);
content.showTextAligned(Element.ALIGN_LEFT, markText, x, y, rotation);
}
private static float getBottomY(MarkInfo markInfo, float height, PdfContentByte content) {
final String markText = markInfo.getMarkText();
float textLength = content.getEffectiveStringWidth(markText, false);
final float rotation = markInfo.getRotation();
float bottomMargin = markInfo.getYMargin() * LEN_TO_PX;
if (rotation >= 0) {
return bottomMargin;
}
return bottomMargin - textLength * sin(rotation);
}
private static float getCenterY(MarkInfo markInfo, float height, PdfContentByte content) {
final String markText = markInfo.getMarkText();
float textLength = content.getEffectiveStringWidth(markText, false);
final float rotation = markInfo.getRotation();
final float yLen = textLength * sin(rotation);
final float halfSize = markInfo.getFontSize() / 2f;
return (height - yLen) / 2 + halfSize * (1 - cos(rotation));
}
private static float getTopY(MarkInfo markInfo, float height, PdfContentByte content) {
final String markText = markInfo.getMarkText();
float textLength = content.getEffectiveStringWidth(markText, false);
final int fontSize = markInfo.getFontSize();
final float rotation = markInfo.getRotation();
float topMargin = markInfo.getYMargin() * LEN_TO_PX;
if (rotation >= 0) {
return height - topMargin - fontSize * cos(rotation) - textLength * sin(rotation);
}
return height - topMargin - fontSize * cos(rotation);
}
private static float getRightX(MarkInfo markInfo, float width, PdfContentByte content) {
final String markText = markInfo.getMarkText();
float textLength = content.getEffectiveStringWidth(markText, false);
final int fontSize = markInfo.getFontSize();
final float rotation = markInfo.getRotation();
final float rightMargin = markInfo.getXMargin() * LEN_TO_PX;
if (rotation >= 0) {
return width - rightMargin - textLength * cos(rotation);
}
return width - rightMargin - textLength * cos(rotation) + fontSize * sin(rotation);
}
private static float getCenterX(MarkInfo markInfo, float width, PdfContentByte content) {
final String markText = markInfo.getMarkText();
float textLength = content.getEffectiveStringWidth(markText, false);
final float halfSize = markInfo.getFontSize() / 2f;
final float rotation = markInfo.getRotation();
final float xLen = textLength * cos(rotation);
return (width - xLen) / 2 + halfSize * sin(rotation);
}
private static float getLeftX(MarkInfo markInfo, float width, PdfContentByte content) {
final int fontSize = markInfo.getFontSize();
final float rotation = markInfo.getRotation();
float leftMargin = markInfo.getXMargin() * LEN_TO_PX;
if (rotation <= 0) {
return leftMargin;
}
return leftMargin + fontSize * sin(rotation);
}
private static void tile(MarkInfo markInfo, float height, float width, PdfContentByte content) {
float textLength = content.getEffectiveStringWidth(markInfo.getMarkText(), false);
final int fontSize = markInfo.getFontSize();
float x = (width - textLength) / 2;
float y = (height - fontSize) / 2;
final float radius = (float) Math.sqrt(height * height + width * width) / 2f;
final float xOffset = textLength + LEN_OFFSET;
final float yOffset = markInfo.getLineSpacing() * fontSize;
final float centerX = width / 2;
float textCenterX = x + textLength / 2;
float relativeX = Math.abs(textCenterX - centerX);
while (relativeX < radius) {
x -= xOffset;
textCenterX = x + textLength / 2;
relativeX = Math.abs(textCenterX - centerX);
}
diffusion(x, y, 1, 1, markInfo, height, width, content);
diffusion(x - xOffset * TILE_MALPOSITION, y - yOffset, 1, -1, markInfo, height, width, content);
}
private static void diffusion(float x, float y, int xDirection, int yDirection, MarkInfo markInfo, float height, float width, PdfContentByte content) {
final float rotation = markInfo.getRotation();
final float sin = sin(rotation);
final float cos = cos(rotation);
float textLength = content.getEffectiveStringWidth(markInfo.getMarkText(), false);
final int fontSize = markInfo.getFontSize();
final float radius = (float) Math.sqrt(height * height + width * width) / 2f;
final float xOffset = textLength + LEN_OFFSET;
final float yOffset = markInfo.getLineSpacing() * fontSize;
final float centerX = width / 2;
final float centerY = height / 2;
final float xLen = textLength * cos;
final float yLen = textLength * sin;
float textCenterX = x + textLength / 2;
float textCenterY = y + fontSize / 2f;
float relativeY = Math.abs(textCenterY - centerY);
if (relativeY > radius) {
return;
}
float relativeX = Math.abs(textCenterX - centerX);
float preRelativeX = relativeX;
while (relativeX > radius) {
x += xOffset * xDirection;
textCenterX = x + textLength / 2;
relativeX = Math.abs(textCenterX - centerX);
if (relativeX > preRelativeX) {
break;
}
preRelativeX = relativeX;
}
while (relativeX < radius) {
float newX = (x - centerX) * cos - (y - centerY) * sin + centerX;
float newY = (x - centerX) * sin + (y - centerY) * cos + centerY;
x += xOffset * xDirection;
textCenterX = x + textLength / 2;
relativeX = Math.abs(textCenterX - centerX);
boolean outOfRange = (newX < 0 && newX + xLen < 0)
|| (newX > width && (newX + xLen) > width)
|| (newY < 0 && (newY + yLen < 0))
|| (newY > height && ((newY + yLen) > height));
if (outOfRange) {
continue;
}
content.showTextAligned(Element.ALIGN_LEFT, markInfo.getMarkText(), newX, newY, rotation);
}
float offset = Math.min(xOffset * TILE_MALPOSITION, 200);
x += offset * yDirection;
xDirection *= -1;
y += yOffset * yDirection;
diffusion(x, y, xDirection, yDirection, markInfo, height, width, content);
}
private static float sin(float rotation) {
return (float) Math.sin(Math.toRadians(rotation));
}
private static float cos(float rotation) {
return (float) Math.cos(Math.toRadians(rotation));
}
private static BaseFont getFont(String fontFamily) throws IOException, DocumentException {
BaseFont baseFont = FONT_MAP.get(fontFamily);
if (baseFont == null) {
String fontName = "fonts/SimSun.ttf";
switch (fontFamily) {
case "NSimSun":
fontName = "fonts/simsun_new.ttf";
break;
case "SimHei":
fontName = "fonts/SIMHEI.TTF";
break;
case "KaiTi":
fontName = "fonts/simkai.ttf";
break;
default:
}
if (SystemUtils.isLinux()) {
fontName = "/usr/share/" + fontName;
baseFont = BaseFont.createFont(fontName, BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
} else {
baseFont = BaseFont.createFont(PdfWaterMarkUtil.class.getClassLoader().getResource(fontName).getPath(), BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
}
FONT_MAP.put(fontFamily, baseFont);
}
return baseFont;
}
public static class Color {
public static final int BLANK = 1;
public static final int RED = 2;
public static final int BLUE = 3;
public static BaseColor get(int fontColor) {
switch (fontColor) {
case BLANK:
return BaseColor.BLACK;
case RED:
return BaseColor.RED;
default:
return BaseColor.BLUE;
}
}
}
@Data
public static class MarkInfo {
private String markText;
private String fontFamily = "SimSun";
private int fontSize = 12;
private int fontColor = 1;
private int pellucidity = 30;
private int positionType = 0;
private float rotation = 45;
private float xMargin = 3;
private float yMargin = 2;
private float lineSpacing = 5f;
}
}
测试,使用这个加水印的工具类,需要保证项目里面已有对应的字体
public static void main(String[] args) throws Exception {
try (final FileInputStream is = new FileInputStream(new File("1.pdf"));
FileOutputStream out = new FileOutputStream(new File("test444.pdf"))
) {
String s = "中国";
final PdfReader reader = new PdfReader(is);
MarkInfo m1 = new MarkInfo();
m1.setPellucidity(45);
m1.setPositionType(TILE);
m1.setFontColor(Color.BLUE);
m1.setFontFamily("KaiTi");
m1.setMarkText(s);
m1.setFontSize(18);
m1.setRotation(30);
m1.setXMargin(1f);
m1.setYMargin(0.1f);
final MarkInfo m2 = WrappedBeanCopier.copyProperties(m1, MarkInfo.class);
m2.setRotation(30);
m2.setFontFamily("NSimSun");
m2.setPositionType(TOP_CENTER);
final MarkInfo m3 = WrappedBeanCopier.copyProperties(m1, MarkInfo.class);
m3.setRotation(45);
m3.setFontFamily("SimHei");
m2.setPositionType(TOP_CENTER);
final MarkInfo m4 = WrappedBeanCopier.copyProperties(m1, MarkInfo.class);
m4.setRotation(60);
final MarkInfo m5 = WrappedBeanCopier.copyProperties(m1, MarkInfo.class);
m5.setRotation(90);
final MarkInfo m6 = WrappedBeanCopier.copyProperties(m1, MarkInfo.class);
m6.setRotation(-30);
final MarkInfo m7 = WrappedBeanCopier.copyProperties(m1, MarkInfo.class);
m7.setRotation(-45);
final MarkInfo m8 = WrappedBeanCopier.copyProperties(m1, MarkInfo.class);
m8.setRotation(-60);
final MarkInfo m9 = WrappedBeanCopier.copyProperties(m1, MarkInfo.class);
m9.setRotation(-90);
List<MarkInfo> list = new ArrayList<>();
list.add(m1);
addWaterMark(reader, out, list);
}
}```
## 效果图
![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/ef7014d2b7eb4e519d244e5da35745ca.png)