Watermarking with PDFBox

前端 未结 6 1611
说谎
说谎 2020-11-28 09:12

I am trying to add a watermark to a PDF specifically with PDFBox. I\'ve been able to get the image to appear on each page, but it loses the background transparency because i

相关标签:
6条回答
  • 2020-11-28 09:23

    Look at this method, whitch add a watermark image in pdf sources using PDFBOX library

    /**
         * 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();
        }
    
    0 讨论(0)
  • 2020-11-28 09:34

    There is another Overlay class within util package, that saves you from creating a pdf with same number of pages as the source document and then doing the overlay.

    To understand its usage, take a look at pdfbox source code, specifically the OverlayPDF class.

    0 讨论(0)
  • 2020-11-28 09:35

    This is how I was able to add a text watermark with the date using PdfBox 2.0.x in C#. It centres the watermark at the top of the page.

    public static void AddWatermark(string fileName)
            {
                StringBuilder sb = new StringBuilder();
                sb.Append("watermark_text  ");
                sb.Append(DateTime.Now.ToString());
    
                string waterMarkText = sb.ToString();
    
                PDDocument origDoc = PDDocument.load(new java.io.File(fileName));
                PDPageTree allPages = origDoc.getPages();
                PDFont font = PDType1Font.HELVETICA_BOLD;
                for (int i = 0, len = allPages.getCount(); i < len; ++i)
                {
                    PDPage pg = (PDPage)allPages.get(i);
    
                    AddWatermarkText(origDoc, pg, font, waterMarkText);
                }
    
                origDoc.save(fileName);
                origDoc.close();
            }
    
    static void AddWatermarkText(PDDocument doc, PDPage page, PDFont font, string text)
            {
                using (PDPageContentStream cs = new PDPageContentStream(doc, page, PDPageContentStream.AppendMode.APPEND, true, true))
                {
                    float fontHeight = 30;
                    float width = page.getMediaBox().getWidth();
                    float height = page.getMediaBox().getHeight();
                    float stringWidth = font.getStringWidth(text) / 1000 * fontHeight;
    
                    float x = (width / 2) - (stringWidth / 2);
                    float y = height - 25;
    
                    cs.setFont(font, fontHeight);
    
                    PDExtendedGraphicsState gs = new PDExtendedGraphicsState();
                    gs.setNonStrokingAlphaConstant(new java.lang.Float(0.2f));
                    gs.setStrokingAlphaConstant(new java.lang.Float(0.2f));
                    gs.setBlendMode(BlendMode.MULTIPLY);
                    gs.setLineWidth(new java.lang.Float(3f));
                    cs.setGraphicsStateParameters(gs);
    
                    cs.setNonStrokingColor(Color.red);
                    cs.setStrokingColor(Color.red);
    
                    cs.beginText();
                    cs.newLineAtOffset(x, y);
                    cs.showText(text);
                    cs.endText();
                }
            }
    

    pdfbox c# watermark pdf

    0 讨论(0)
  • 2020-11-28 09:37

    @Androidman : Addition to https://stackoverflow.com/a/9382212/7802973

    It seems like many methods are removed with each version of PDFBox. So that code will not work on 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")
    

    Instead, use void org.apache.pdfbox.pdmodel.PDDocument.save(String fileName), I think:

    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();
    

    Edit: I am using org.apache.pdfbox.tools.OverlayPDF for overlays now and it works just fine. The code looks like this:

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

    As I had not enough reputation to add a comment, I thought it'd be appropiate to add this in a new answer.

    0 讨论(0)
  • 2020-11-28 09:38

    Just made this piece of code to add (transparent) images (jpg, png, gif) to a pdf page with 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();
    }
    

    Example:

    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 worked for me with jdk 1.7 and bcmail-jdk16-140.jar, bcprov-jdk16-140.jar, commons-logging-1.1.3.jar, fontbox-1.8.3.jar, jempbox-1.8.3.jar and pdfbox-1.8.3.jar.

    0 讨论(0)
  • 2020-11-28 09:41

    UPDATED ANSWER (Better version with easy way to watermark, thanks to the commentators below and @okok who provided input with his answer)

    If you are using PDFBox 1.8.10 or above, you can add watermark to your PDF document easily with better control over what pages needs to be watermarked. Assuming you have a one page PDF document that has the watermark image, you can overlay this on the document you want to watermark as follows.

    Sample Code using 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.
    

    Sample using PDFBox 2.0.0 Release candidate

    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);      
        }
    }
    

    If you want to use the new package org.apache.pdfbox.tools.OverlayPDF for overlays you can do this way. (Thanks the poster below)

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

    OLD ANSWER Inefficient way, not recommended.

    Well, OP asked how to do it in PDFBox, the first answer looks like an example using iText. Creating a watermark in PDFBox is really simple. The trick is, you should have an empty PDF document with the watermark image. Then all you have to do is Overlay this watermark document on the document that you want to add the watermark to.

    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");
    

    Caution: You should make sure you match the number of pages in both document..Otherwise, you would end up with a document with number of pages matching the one which has least number of pages. You can manipulate the watermark document and duplicate the pages to match your document.

    Hope this helps.!

    0 讨论(0)
提交回复
热议问题