You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何调整文本或图片角度?PDFBox旋转水印出现偏移怎么解决

问题原因

你当前的旋转偏移是因为Matrix.getRotateInstance()的后两个参数设置为(0,0),代表围绕PDF页面默认的坐标原点(左下角)旋转,旋转后文本坐标系被整体偏转,自然会偏离预期位置。

解决方法

PDFBox的Matrix类本身就支持自定义旋转锚点生成旋转矩阵,不需要额外工具,只需要调整旋转锚点为你期望的水印旋转中心即可,步骤如下:

  • 先计算水印文本的实际宽度,配合字体大小得到文本的实际占据尺寸
  • 确定你期望的水印放置位置,以该位置下的水印自身中心/你指定的点作为旋转锚点
  • 生成旋转矩阵时传入该锚点坐标即可

修改后可正常使用的代码如下:

public static void addTextWatermark(PDDocument doc, PDPage page, PDFont font, TextParam param)
            throws IOException {
        try (PDPageContentStream cs
                     = new PDPageContentStream(doc, page, PDPageContentStream.AppendMode.APPEND, true, true)) {
            // 1. 获取页面尺寸,若页面有自定义裁剪区域可替换为getCropBox()
            PDRectangle pageRect = page.getMediaBox();
            float pageWidth = pageRect.getWidth();
            float pageHeight = pageRect.getHeight();
            float fontSize = param.getFontSize();
            
            // 2. 计算文本实际宽度
            float textWidth = font.getStringWidth(param.getText()) / 1000 * fontSize;
            
            // 3. 定义水印放置的目标位置,示例为页面居中,可自行修改为其他坐标
            float targetX = (pageWidth - textWidth) / 2;
            float targetY = (pageHeight - fontSize) / 2;
            
            // 4. 旋转锚点设为水印自身的中心,保证旋转时水印围绕自身中心转,不会偏移位置
            float anchorX = targetX + textWidth / 2;
            float anchorY = targetY + fontSize / 2;
            
            // 替换原来的旋转代码,传入自定义锚点
            cs.transform(Matrix.getRotateInstance(Math.toRadians(param.getDegree()), anchorX, anchorY));
            
            cs.setFont(font, fontSize);
            PDExtendedGraphicsState gs = new PDExtendedGraphicsState();
            gs.setNonStrokingAlphaConstant(param.getDissolve() / 100f);
            gs.setStrokingAlphaConstant(param.getDissolve() / 100f);

            gs.setBlendMode(BlendMode.MULTIPLY);
            gs.setLineWidth(3f);
            cs.setGraphicsStateParameters(gs);

            //设置字体和边框颜色
            cs.setNonStrokingColor(new Color(param.getFills()[0], param.getFills()[1], param.getFills()[2]));
            cs.setStrokingColor(new Color(param.getFills()[0], param.getFills()[1], param.getFills()[2]));

            cs.beginText();
            // 这里传入目标位置坐标即可
            cs.newLineAtOffset(targetX, targetY);
            cs.showText(param.getText());
            cs.endText();
        }
    }
额外说明

如果需要放置图片水印,逻辑完全一致:先拿到图片的宽高,确定图片放置的目标坐标,再以图片中心为锚点生成旋转矩阵即可。

内容的提问来源于stack exchange,提问作者markjrzhang

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.24 05:45:05