2012-01-19 12 views
14

Sto tentando di aggiungere una filigrana a un PDF specificamente con PDFBox. Sono riuscito a far apparire l'immagine su ogni pagina, ma perde la trasparenza dello sfondo perché sembra che PDJpeg lo converta in JPG. Forse c'è un modo per farlo usando PDXObjectImage.Filigrana con PDFBox

Ecco quello che ho scritto finora:

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(); 
    } 
} 
+0

Problema con la risposta di sotto è che il posizionamento non funziona come mi aspetterei (giustificato in alto a sinistra) se le pagine sono di dimensioni diverse. Avevo bisogno di aggiungere una filigrana di testo all'inizio di ogni pagina in un documento PDF, e la soluzione di cui sopra era esattamente ciò di cui avevo bisogno, quindi ho risolto questa soluzione. –

risposta

26

RISPOSTA AGGIORNATO (versione migliore con un modo semplice per filigrana, grazie ai commentatori di seguito e @okok che ha fornito input con la sua risposta)

Se si utilizza PDFBox 1.8.10 o versione successiva, è possibile aggiungere facilmente filigrana al documento PDF con un controllo migliore su quali pagine devono essere sottoposte a filigrana. Supponendo che si disponga di un documento PDF di una pagina con l'immagine della filigrana, è possibile sovrapporlo al documento che si desidera filigranare come segue.

codice di esempio utilizzando 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. 

di esempio utilizzando 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);  
    } 
} 

VECCHIO RISPOSTA modo inefficiente, non è raccomandato.

Bene, OP ha chiesto come farlo in PDFBox, la prima risposta sembra un esempio con iText. Creare una filigrana in PDFBox è davvero semplice. Il trucco è che dovresti avere un documento PDF vuoto con l'immagine della filigrana. Quindi tutto ciò che devi fare è Sovrapporre questo documento filigrana sul documento a cui vuoi aggiungere la filigrana.

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

Attenzione: È necessario assicurarsi di abbinare il numero di pagine in entrambi document..Otherwise, si finirebbe con un documento con il numero di pagine che corrispondono quello che ha minor numero di pagine. È possibile manipolare il documento filigrana e duplicare le pagine in modo che corrispondano al documento.

Spero che questo aiuti.!

+0

Siamo spiacenti per la risposta in ritardo (il progetto è stato messo in attesa). Ho provato a implementare questo codice, ma ottengo uno dei due problemi: (1) Ho usato un PDF di 1 pagina e un PDF di filigrana di 1 pagina, ma la filigrana era l'unica cosa da mostrare sul documento finale (forse qualche tipo di trasparenza?) (2) Ho provato un PDF di 2 pagine con un PDF di filigrana di 2 pagine e continuo a ottenere "Pagine di layout con COSArray attualmente non supportato". Non sono riuscito a trovare alcuna documentazione su di esso o come modificare il documento multi-pagina in un formato più adatto. – aosmith

+0

Dopo aver giocato ancora con questo, sembra funzionare bene, ma solo in particolari scenari. La filigrana non sembra funzionare bene se si tratta di qualcosa di diverso dal testo (non è possibile ottenere la trasparenza per funzionare neanche). La sovrapposizione inoltre non può contenere COSArray (di cui non sono ancora sicuro da dove provenga, forse correlato a segnalibri o testo). – aosmith

+0

Ciao - Esiste una soluzione per filigrane di pagine specifiche sul PDF e non tutte? –

-3

Guardate questo metodo, a tuute aggiungere un'immagine della filigrana fonti pdf usando la libreria 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(); 
    } 
+2

Questo è per iText –

+0

Come lo faresti con Rails? –

9

appena fatto questo pezzo di codice per aggiungere immagini (trasparenti) (jpg, png, gif) ad una pagina PDF con 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(); 
} 

Esempio:

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

Questo ha funzionato per me con jdk 1.7 e bcmail-jdk16-140.jar, bcprov-jdk16-140.jar, commons-logging-1.1.3.jar, fontbox-1.8.3.jar, jempbox-1.8.3.jar e pdfbox-1.8. 3.jar.

+0

Se si utilizza Android che non supporta BufferedImage e PdfBox-versione Android 1.8.9.1 che non ha ancora PDPixelMap, è possibile creare PDXObjectImage da una bitmap: PDImageXObject ximage = LosslessFactory.createFromImage (documento, bitmap); – jk7

0

C'è un'altra classe Overlay all'interno del pacchetto util, che ti evita di creare un pdf con lo stesso numero di pagine del documento sorgente e quindi di eseguire l'overlay.

Per comprenderne l'utilizzo, dare un'occhiata al codice sorgente pdfbox, in particolare la classe OverlayPDF.

2

@Androidman: Aggiunta di https://stackoverflow.com/a/9382212/7802973

Sembra che molti metodi vengono rimossi con ogni versione di PDFBox. Quindi quel codice non funzionerà su 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") 

Invece, utilizzare void org.apache.pdfbox.pdmodel.PDDocument.save(String fileName), penso:

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: Sto usando org.apache.pdfbox.tools.OverlayPDF per le sovrapposizioni ora e funziona bene. Il codice è simile al seguente:

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

Come ho avuto abbastanza reputazione per aggiungere un commento, ho pensato che sarebbe appropriata per aggiungere questo in una nuova risposta.