有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java如何在运行时覆盖两个文档

我需要在运行时添加水印文本,即在创建文档时,我需要添加水印文本。我最初的方法是从文档中获取所有页面,并在这些页面上添加我的文本。Id确实有效,但问题是,无论我的水印消息来自哪里,它都会隐藏我的页面内容。请参阅我的初始方法代码

  List pages = document.getDocumentCatalog().getAllPages();
    float fontSize = 70.0f;
    for (int i = 0; i < pages.size(); i++) {
        PDPage page = (PDPage) pages.get(i);
        PDRectangle pageSize = page.findMediaBox();
        float stringWidth = pdfFont.getStringWidth(text) * fontSize
                / 1000f;
        // calculate to center of the page
        int rotation = page.findRotation();
        boolean rotate = degree > 0;
        float pageWidth = rotate ? pageSize.getHeight() : pageSize
                .getWidth();
        float pageHeight = rotate ? pageSize.getWidth() : pageSize
                .getHeight();
        double centeredXPosition = rotate ? pageHeight / 2f
                : (pageWidth - stringWidth) / 2f;
        double centeredYPosition = rotate ? (pageWidth - stringWidth) / 2f
                : pageHeight / 2f;
        // append the content to the existing stream
        PDPageContentStream contentStream = new PDPageContentStream(
                document, page, true, true, true);
        contentStream.beginText();
        // set font and font size
        contentStream.setFont(pdfFont, fontSize);
        // set text color to red
        contentStream.setNonStrokingColor(240, 240, 240);
        if (rotate) {
            // rotate the text according to the page rotation
            contentStream.setTextRotation(degree, x, y);
        } else {
            contentStream.setTextTranslation(centeredXPosition,
                    centeredYPosition);
        }
        contentStream.drawString(text);
        contentStream.endText();
        contentStream.close();

我读过关于Overlay的书,也尝试过它,所以我试着改变我的方法,因为我认为只有Overlay才能满足我的要求。我目前的做法是:

    public PDDocument createWatermarkText() {
    PDDocument watermarkDoc = new PDDocument();
    PDPage watermarkPage = new PDPage();
    try {

        watermarkDoc.addPage(watermarkPage);
        PDPageContentStream content = new PDPageContentStream(watermarkDoc,
                watermarkPage);
        content.setFont(pdfFont, fontSize);
        content.beginText();
        content.moveTextPositionByAmount(x, y);
        content.setNonStrokingColor(255, 0, 0);
        PDRectangle pageSize = watermarkPage.findMediaBox();
        float stringWidth = pdfFont.getStringWidth(text) * fontSize / 1000f;
        // int rotation = page.findRotation();
        boolean rotate = degree > 0;
        float pageWidth = rotate ? pageSize.getHeight() : pageSize
                .getWidth();
        float pageHeight = rotate ? pageSize.getWidth() : pageSize
                .getHeight();
        double centeredXPosition = rotate ? pageHeight / 2f
                : (pageWidth - stringWidth) / 2f;
        double centeredYPosition = rotate ? (pageWidth - stringWidth) / 2f
                : pageHeight / 2f;
        content.setTextRotation(degree, x, y);

        content.drawString(text);
        content.endText();
        content.close();
        // ColumnText.showTextAligned(writer.getDirectContentUnder(), align,
        // new Phrase(text, pdfFont), x, y,
        // degree);
    } catch (IOException e) {
        e.printStackTrace();
    }
    return watermarkDoc;
}

然后调用这个方法

     PDDocument wDoc = createWatermarkText();
            //document.addPage(page);
             Overlay overlay = new Overlay();

             overlay.overlay(wDoc, document);

但这种方法行不通,我得到的是空白pdf。非常感谢您的帮助


共 (1) 个答案

  1. # 1 楼答案

    这个答案试图让OP的原始方法发挥作用

    原始方法的问题

    where ever my watermark message comes it is hiding my page content.

    这是因为PDFBoxPDPageContentStream构造函数将新流添加为lastcontent stream,因此其操作也会最后执行,从而覆盖之前绘制的内容

    因此,为了将新内容推到现有内容之下,我们必须将新内容流移动到页面内容流中的前端位置

    为了能够做到这一点,我首先更改现有代码:我将水印绘图代码括在saveGraphicsStaterestoreGraphicsState中。这是必要的,以保护原始内容不受标记绘图代码状态变化的影响,例如文本颜色变化

    ...
    PDPageContentStream contentStream = new PDPageContentStream(
            document, page, true, true, true);
    contentStream.saveGraphicsState();
    contentStream.beginText();
    // set font and font size
    contentStream.setFont(pdfFont, fontSize);
    // set text color to red
    contentStream.setNonStrokingColor(240, 240, 240);
    if (rotate) {
        // rotate the text according to the page rotation
        contentStream.setTextRotation(degree, x, y);
    } else {
        contentStream.setTextTranslation(centeredXPosition,
                centeredYPosition);
    }
    contentStream.drawString(text);
    contentStream.endText();
    contentStream.restoreGraphicsState();
    contentStream.close();
    ...
    

    有了这一变化,我们只需要调用以下方法来将水印推送到预先存在的内容下:

    void pushUnder(PDDocument document)
    {
        List<?> pages = document.getDocumentCatalog().getAllPages();
        float fontSize = 70.0f;
        for (int i = 0; i < pages.size(); i++) {
            PDPage page = (PDPage) pages.get(i);
            COSBase contents = page.getCOSDictionary().getDictionaryObject(COSName.CONTENTS);
            if (contents instanceof COSStreamArray)
            {
                COSStreamArray contentsArray = (COSStreamArray) contents;
                COSArray newArray = new COSArray();
                newArray.add(contentsArray.get(0));
                newArray.add(contentsArray.get(contentsArray.getStreamCount() - 1));
    
                for (int j = 1; j < contentsArray.getStreamCount() - 1; j++)
                {
                    newArray.add(contentsArray.get(j));
                }
    
                COSStreamArray newStreamArray = new COSStreamArray(newArray);
                page.getCOSDictionary().setItem(COSName.CONTENTS, newStreamArray);
            }
        }
    }
    

    UnderlayText.java

    (如果你仔细观察这个方法,你会发现我们不会把新的流移到第一个位置,而是只移到第二个位置。我们这样做是因为new PDPageContentStream(document, page, true, true, true)构造函数调用实际上创建了两个新流,一个在第一个位置,一个在最后一个位置,第一个保存图形状态,最后一个恢复图形状态,然后包含操作。在前者之前移动后者将导致在开始时恢复图形状态操作,这将是一个错误。)