2012-01-19 103 views
14

Estoy tratando de agregar una marca de agua a un PDF específicamente con PDFBox. He podido hacer que la imagen aparezca en cada página, pero pierde la transparencia de fondo porque parece como si PDJpeg la convirtiera en un JPG. Quizás haya una manera de hacerlo usando PDXObjectImage.Marca de agua con PDFBox

Aquí es lo que he escrito hasta ahora:

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

El problema con la respuesta a continuación es que el posicionamiento no funciona como era de esperar (arriba a la izquierda justificado) si las páginas tienen dimensiones diferentes. Necesitaba agregar una marca de agua de texto a la parte superior de cada página en un documento PDF, y la solución anterior era exactamente lo que necesitaba, por lo que se mejoró esta solución. –

Respuesta

26

RESPUESTA ACTUALIZADO (mejor versión con una manera fácil de filigrana, gracias a los comentaristas a continuación y @okok que proporcionó información con su respuesta)

Si está utilizando PDFBox 1.8.10 o superior, puede agregar marcas de agua a su documento PDF fácilmente con un mejor control sobre qué páginas deben marcarse con una marca de agua. Suponiendo que tiene un documento PDF de una página que tiene la imagen de marca de agua, puede superponer esto en el documento que desea filmar de la siguiente manera.

Código de ejemplo usando 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. 

de muestras mediante 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);  
    } 
} 

vieja respuesta forma ineficiente, no se recomienda.

Bueno, OP preguntó cómo hacerlo en PDFBox, la primera respuesta parece un ejemplo con iText. Crear una marca de agua en PDFBox es realmente simple. El truco es que debe tener un documento PDF vacío con la imagen de marca de agua. Entonces todo lo que tiene que hacer es superponer este documento de marca de agua en el documento al que desea agregar la marca de agua.

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

Precaución: Debe asegurarse de que coinciden con el número de páginas en tanto document..Otherwise, que terminaría con un documento con el número de páginas que coincidan con el que tiene menor número de páginas. Puede manipular el documento de marca de agua y duplicar las páginas para que coincida con su documento.

Espero que esto ayude.!

+0

Disculpa por la respuesta tardía (el proyecto se puso en espera). Intenté implementar este código, pero tengo uno de dos problemas: (1) Usé un PDF de 1 página y un PDF de marca de agua de 1 página, pero la marca de agua era lo único que aparecía en el documento final (tal vez algún tipo de la cuestión de la transparencia?) (2) Intenté un PDF de 2 páginas con un PDF de marca de agua de 2 páginas y seguí recibiendo "Páginas de diseño con COSArray actualmente no compatible". No pude encontrar ninguna documentación sobre él o cómo cambiar el documento de varias páginas en un formato más adecuado. – aosmith

+0

Después de jugar con esto un poco más, parece funcionar bien, pero solo en escenarios particulares. La marca de agua no parece funcionar bien si se trata de algo más que texto (tampoco se pudo lograr que la transparencia funcione). La superposición tampoco puede tener COSArray (que todavía no estoy seguro de dónde viene, tal vez relacionado con marcadores o texto). – aosmith

+0

Hola: ¿Existe alguna solución para las páginas específicas de marcas de agua en el PDF y no todas? –

-3

mirada a este método, générale añadir una imagen de marca de agua en las fuentes PDF utilizando la biblioteca 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

Esto es para iText –

+0

¿Cómo harías esto con Rails? –

9

acaba de hacer esta pieza de código para agregar imágenes (transparente) (JPG, PNG, GIF) a una página 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(); 
} 

Ejemplo:

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

Esto funcionó para mí con jdk 1.7 y bcmail-jdk16-140.jar, bcprov-jdk16-140.jar, commons-logging-1.1.3.jar, fontbox-1.8.3.jar, jempbox-1.8.3.jar y pdfbox-1.8. 3.jar.

+0

Si usa Android que no admite BufferedImage, y PdfBox-Android versión 1.8.9.1 que aún no tiene PDPixelMap, PDXObjectImage se puede crear a partir de un mapa de bits: PDImageXObject ximage = LosslessFactory.createFromImage (document, bitmap); – jk7

0

Hay otra clase Overlay dentro del paquete util, que le ahorra la creación de un pdf con el mismo número de páginas que el documento original y luego la superposición.

Para comprender su uso, eche un vistazo al código fuente pdfbox, específicamente la clase OverlayPDF.

2

@Androidman: Adición a https://stackoverflow.com/a/9382212/7802973

Parece que muchos métodos se eliminan con cada versión de PDFBox. Entonces ese código no funcionará en 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") 

su lugar, utilice void org.apache.pdfbox.pdmodel.PDDocument.save(String fileName), pienso:

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

Editar: estoy usando org.apache.pdfbox.tools.OverlayPDF para superposiciones ahora y funciona muy bien. El código es el siguiente:

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

Como tenía la reputación no es suficiente para agregar un comentario, pensé que sería apropiado añadir esta en una nueva respuesta.

Cuestiones relacionadas