Водяной знак с PDFBox - PullRequest
       59

Водяной знак с PDFBox

19 голосов
/ 19 января 2012

Я пытаюсь добавить водяной знак в PDF-файл специально с помощью PDFBox.Я смог заставить изображение появляться на каждой странице, но оно теряет прозрачность фона, потому что кажется, что PDJpeg преобразует его в JPG.Возможно, есть способ сделать это, используя PDXObjectImage.

Вот что я написал до сих пор:

public static void watermarkPDF(PDDocument pdf) throws IOException
{
    // Load watermark
    BufferedImage buffered = ImageIO.read(new File("C:\\PDF_Test\\watermark.png"));
    PDJpeg watermark = new PDJpeg(pdf, buffered);

    // Loop through pages in PDF
    List pages = pdf.getDocumentCatalog().getAllPages();
    Iterator iter = pages.iterator();
    while(iter.hasNext())
    {
        PDPage page = (PDPage)iter.next();

        // Add watermark to individual page
        PDPageContentStream stream = new PDPageContentStream(pdf, page, true, false);
        stream.drawImage(watermark, 100, 0);
        stream.close();
    }

    try 
    {
        pdf.save("C:\\PDF_Test\\watermarktest.pdf");
    } 
    catch (COSVisitorException e) 
    {
        e.printStackTrace();
    }
}

Ответы [ 5 ]

29 голосов
/ 21 февраля 2012

ОБНОВЛЕННЫЙ ОТВЕТ (Лучшая версия с простым способом добавления водяных знаков, благодаря нижеприведенным комментаторам и @okok, предоставившим свои ответы)

Если вы используете PDFBox 1.8.10 иливыше, вы можете легко добавить водяной знак в ваш PDF документ с лучшим контролем над тем, какие страницы должны быть водяными знаками.Предполагая, что у вас есть одностраничный PDF-документ с изображением водяного знака, вы можете наложить его на документ, который вы хотите сделать водяным знаком, следующим образом.

Образец кода с использованием 1.8.10

import java.util.HashMap;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.util.Overlay;

public class TestPDF {
    public static void main(String[] args) throws Exception{
            PDDocument realDoc = PDDocument.load("originaldocument.pdf"); 
            //the above is the document you want to watermark                   

            //for all the pages, you can add overlay guide, indicating watermark the original pages with the watermark document.
            HashMap<Integer, String> overlayGuide = new HashMap<Integer, String>();
            for(int i=0; i<realDoc.getPageCount(); i++){
                overlayGuide.put(i+1, "watermark.pdf");
                //watermark.pdf is the document which is a one page PDF with your watermark image in it. Notice here that you can skip pages from being watermarked.
            }
            Overlay overlay = new Overlay();
            overlay.setInputPDF(realDoc);
            overlay.setOutputFile("final.pdf");
            overlay.setOverlayPosition(Overlay.Position.BACKGROUND);
            overlay.overlay(overlayGuide,false);
           //final.pdf will have the original PDF with watermarks.

Образец с использованием PDFBox 2.0.0 Кандидат на выпуск

import java.io.File;
import java.util.HashMap;
import org.apache.pdfbox.multipdf.Overlay;
import org.apache.pdfbox.pdmodel.PDDocument;

public class TestPDF {

    public static void main(String[] args) throws Exception{        
        PDDocument realDoc = PDDocument.load(new File("originaldocument.pdf"));
        //the above is the document you want to watermark
        //for all the pages, you can add overlay guide, indicating watermark the original pages with the watermark document.

        HashMap<Integer, String> overlayGuide = new HashMap<Integer, String>();
        for(int i=0; i<realDoc.getNumberOfPages(); i++){
            overlayGuide.put(i+1, "watermark.pdf");
            //watermark.pdf is the document which is a one page PDF with your watermark image in it. 
            //Notice here, you can skip pages from being watermarked.
        }
        Overlay overlay = new Overlay();
        overlay.setInputPDF(realDoc);
        overlay.setOutputFile("final.pdf");
        overlay.setOverlayPosition(Overlay.Position.BACKGROUND);
        overlay.overlay(overlayGuide);      
    }
}

Если вы хотите использовать новый пакет org.apache.pdfbox.tools.OverlayPDF для наложений, вы можете сделать это следующим образом.(Спасибо постеру ниже)

String[] overlayArgs = {"C:/Examples/foreground.pdf", "C:/Examples/background.pdf", "C:/Examples/resulting.pdf"};
OverlayPDF.main(overlayArgs);
System.out.println("Overlay finished.");

СТАРЫЙ ОТВЕТ Неэффективный способ, не рекомендуется.

Ну, ОП спросил, как это сделать в PDFBox,Первый ответ выглядит как пример с использованием iText.Создать водяной знак в PDFBox действительно просто.Хитрость в том, что у вас должен быть пустой документ PDF с изображением водяного знака.Тогда все, что вам нужно сделать, это наложить этот документ с водяным знаком на документ, к которому вы хотите добавить водяной знак.

PDDocument watermarkDoc = PDDocument.load("watermark.pdf");
//Assuming your empty document with watermark image in it.

PDDocument realDoc = PDDocument.load("document-to-be-watermarked.pdf");
//Let's say this is your document that you want to watermark. For example sake, I am opening a new one, you would already have a reference to PDDocument if you are creating one

Overlay overlay = new Overlay();
overlay.overlay(realDoc,watermarkDoc);
watermarkDoc.save("document-now-watermarked.pdf");

Внимание: вы должны убедиться, что вы соответствуете числу страниц в обоих документах .. В противном случае, вы получите документ с числом страниц, совпадающим с тем, у которого наименьшее количество страниц.Вы можете манипулировать документом с водяными знаками и дублировать страницы в соответствии с вашим документом.

Надеюсь, это поможет.!

10 голосов
/ 16 декабря 2013

Только что сделал этот кусок кода, чтобы добавить (прозрачные) изображения (jpg, png, gif) на страницу PDF с pdfbox:

/**
 * Draw an image to the specified coordinates onto a single page. <br>
 * Also scaled the image with the specified factor.
 * 
 * @author Nick Russler
 * @param document PDF document the image should be written to.
 * @param pdfpage Page number of the page in which the image should be written to.
 * @param x X coordinate on the page where the left bottom corner of the image should be located. Regard that 0 is the left bottom of the pdf page.
 * @param y Y coordinate on the page where the left bottom corner of the image should be located.
 * @param scale Factor used to resize the image.
 * @param imageFilePath Filepath of the image that is written to the PDF.
 * @throws IOException
 */
public static void addImageToPage(PDDocument document, int pdfpage, int x, int y, float scale, String imageFilePath) throws IOException {   
    // Convert the image to TYPE_4BYTE_ABGR so PDFBox won't throw exceptions (e.g. for transparent png's).
    BufferedImage tmp_image = ImageIO.read(new File(imageFilePath));
    BufferedImage image = new BufferedImage(tmp_image.getWidth(), tmp_image.getHeight(), BufferedImage.TYPE_4BYTE_ABGR);        
    image.createGraphics().drawRenderedImage(tmp_image, null);

    PDXObjectImage ximage = new PDPixelMap(document, image);

    PDPage page = (PDPage)document.getDocumentCatalog().getAllPages().get(pdfpage);

    PDPageContentStream contentStream = new PDPageContentStream(document, page, true, true);
    contentStream.drawXObject(ximage, x, y, ximage.getWidth()*scale, ximage.getHeight()*scale);
    contentStream.close();
}

Пример:

public static void main(String[] args) throws Exception {
    String pdfFilePath = "C:/Users/Nick/Desktop/pdf-test.pdf";
    String signatureImagePath = "C:/Users/Nick/Desktop/signature.png";
    int page = 0;

    PDDocument document = PDDocument.load(pdfFilePath);

    addImageToPage(document, page, 0, 0, 0.5f, signatureImagePath);

    document.save("C:/Users/Nick/Desktop/pdf-test-neu.pdf");
}

Thisу меня работал с jdk 1.7 и bcmail-jdk16-140.jar, bcprov-jdk16-140.jar, commons-logging-1.1.3.jar, fontbox-1.8.3.jar, jempbox-1.8.3.jar и pdfbox-1.8.3.jar.

2 голосов
/ 11 сентября 2017

@ Androidman: дополнение к https://stackoverflow.com/a/9382212/7802973

Кажется, что многие методы удаляются с каждой версией PDFBox.Так что этот код не будет работать на PDFBox 2.0.7.

Overlay overlay = new Overlay();
overlay.setInputPDF(realDoc);
// ** The method setOutputFile(String) is undefined for the type Overlay ** 
overlay.setOutputFile("final.pdf")

Вместо этого используйте void org.apache.pdfbox.pdmodel.PDDocument.save(String fileName), я думаю:

PDDocument realDoc = PDDocument.load(new File("originaldocument.pdf"));
    //the above is the document you want to watermark
    //for all the pages, you can add overlay guide, indicating watermark the original pages with the watermark document.

HashMap<Integer, String> overlayGuide = new HashMap<Integer, String>();
    for(int i=0; i<realDoc.getNumberOfPages(); i++){
        overlayGuide.put(i+1, "watermark.pdf");
        //watermark.pdf is the document which is a one page PDF with your watermark image in it. 
        //Notice here, you can skip pages from being watermarked.
    }
Overlay overlay = new Overlay();
overlay.setInputPDF(realDoc);
overlay.overlay(overlayGuide).save("final.pdf");
overlay.close();

Редактировать: Я использую org.apache.pdfbox.tools.OverlayPDF для оверлеев, и все работает отлично.Код выглядит следующим образом:

String[] overlayArgs = {"C:/Examples/foreground.pdf", "C:/Examples/background.pdf", "C:/Examples/resulting.pdf"};
OverlayPDF.main(overlayArgs);
System.out.println("Overlay finished.");

Поскольку у меня не было достаточно репутации, чтобы добавить комментарий, я подумал, что было бы целесообразно добавить это в новом ответе.

0 голосов
/ 10 ноября 2015

В пакете утилит есть еще один класс Overlay, который избавляет вас от создания PDF-файла с тем же количеством страниц, что и в исходном документе, и последующего наложения.

Чтобы понять его использование, взгляните на исходный код pdfbox, в частности класс OverlayPDF.

0 голосов
/ 16 февраля 2012

Посмотрите на этот метод, добавьте изображение водяного знака в pdf-источники, используя библиотеку PDFBOX

/**
     * Coloca una imagen como marca de agua en un pdf en una posición especifica
     * 
     * @param buffer
     *            flujo de bytes que contiene el pdf original
     * 
     * @param imageFileName
     *            nombre del archivo de la imagen a colocar
     * 
     * @param x
     *            posición x de la imagen en el pdf
     * 
     * @param y
     *            posición y de la imagen en el pdf
     * 
     * @param under 
     * determina si la marca se pone encima o por debajo de la factura
     * 
     * @return flujo de bytes resultante que contiene el pdf modificado
     * 
     * @throws IOException
     * @throws DocumentException
     */
    public static byte[] addWaterMarkImageToPDF(byte[] buffer,
            String imageFileName, int x, int y, boolean under) throws IOException,
            DocumentException {
        logger.debug("Agregando marca de agua:"+imageFileName);
        PdfReader reader = new PdfReader(buffer);
        ByteArrayOutputStream arrayOutput = new ByteArrayOutputStream();
        OutputStream output = new BufferedOutputStream(arrayOutput);
        PdfStamper stamper = new PdfStamper(reader, output);
        com.lowagie.text.Image img = com.lowagie.text.Image
                .getInstance(imageFileName);
        img.setAbsolutePosition(x, y);
        img.scalePercent(SCALE_PER);
        PdfContentByte pdfContent;
        int total = reader.getNumberOfPages() + 1;
        for (int i = 1; i < total; i++) {
            pdfContent = (under)?stamper.getUnderContent(i):
                stamper.getOverContent(i);
            pdfContent.addImage(img);
        }
        stamper.close();
        output.flush();
        output.close();
        return arrayOutput.toByteArray();
    }
...