Rotate watermark text at 45 degree angle across the center Apache PDFBox

久未见 提交于 2019-12-02 06:06:51

What I do is to first rotate based on the calculated angle. In this "rotated world" I do a horizontal offset so that the text is in the middle, and also move the text vertically a bit lower, so that it is in the "vertical" middle of an imagined diagonal line (horizontal in the "rotated world").

try (PDDocument doc = new PDDocument())
{
    PDPage page = new PDPage();
    doc.addPage(page);

    PDFont font = PDType1Font.HELVETICA_BOLD;
    try (PDPageContentStream cs =
            new PDPageContentStream(doc, page, PDPageContentStream.AppendMode.APPEND, true, true))
        // use this long constructor when working on existing PDFs
    {
        float fontHeight = 110;
        String text = "Watermark";

        float width = page.getMediaBox().getWidth();
        float height = page.getMediaBox().getHeight();
        int rotation = page.getRotation();
        switch (rotation)
        {
            case 90:
                width = page.getMediaBox().getHeight();
                height = page.getMediaBox().getWidth();
                cs.transform(Matrix.getRotateInstance(Math.toRadians(90), height, 0));
                break;
            case 180:
                cs.transform(Matrix.getRotateInstance(Math.toRadians(180), width, height));
                break;
            case 270:
                width = page.getMediaBox().getHeight();
                height = page.getMediaBox().getWidth();
                cs.transform(Matrix.getRotateInstance(Math.toRadians(270), 0, width));
                break;
            default:
                break;
        }
        float stringWidth = font.getStringWidth(text) / 1000 * fontHeight;
        float diagonalLength = (float) Math.sqrt(width * width + height * height);
        float angle = (float) Math.atan2(height, width);
        float x = (diagonalLength - stringWidth) / 2; // "horizontal" position in rotated world
        float y = -fontHeight / 4; // 4 is a trial-and-error thing, this lowers the text a bit
        cs.transform(Matrix.getRotateInstance(angle, 0, 0));
        cs.setFont(font, fontHeight);
        //cs.setRenderingMode(RenderingMode.STROKE); // for "hollow" effect

        PDExtendedGraphicsState gs = new PDExtendedGraphicsState();
        gs.setNonStrokingAlphaConstant(0.2f);
        gs.setStrokingAlphaConstant(0.2f);
        gs.getCOSObject().setItem(COSName.BM, COSName.MULTIPLY);
        // gs.setBlendMode(BlendMode.MULTIPLY); // will work in 2.0.14
        cs.setGraphicsStateParameters(gs);

        // some API weirdness here. When int, range is 0..255.
        // when float, this would be 0..1f
        cs.setNonStrokingColor(255, 0, 0);
        cs.setStrokingColor(255, 0, 0);

        cs.beginText();
        cs.newLineAtOffset(x, y);
        cs.showText(text);
        cs.endText();
    }
    doc.save("watermarked.pdf");
}

Note that I've set both stroking and non stroking (= fill). This is useful for people who want to try the (disabled) "hollow" appearance, that one uses stroking only. The default mode is fill, i.e. non-stroking.

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!