Водяные знаки с PDFBox
Я пытаюсь добавить водяной знак в PDF специально с PDFBox. Мне удалось получить изображение на каждой странице, но оно теряет прозрачность фона, потому что кажется, что PDJpeg преобразует его в JPG. Возможно, есть способ сделать это с помощью PDXObjectImage.
вот что я написал до сих пор:
public static void watermarkPDF(PDDocument pdf) throws IOException
{
// Load watermark
BufferedImage buffered = ImageIO.read(new File("C:PDF_Testwatermark.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_Testwatermarktest.pdf");
}
catch (COSVisitorException e)
{
e.printStackTrace();
}
}
5 ответов
ОБНОВЛЕННЫЙ ОТВЕТ (лучшая версия с простым способом водяного знака, благодаря комментаторам ниже и @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 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);
}
}
если вы хотите использовать новый пакет org.апаш.pdfbox.инструменты.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");
внимание: вы должны убедиться, что вы соответствовать количеству страниц в документе..В противном случае вы получите документ с количеством страниц, соответствующим тому, которое имеет наименьшее количество страниц. Вы можете манипулируйте документом водяных знаков и дублируйте страницы в соответствии с вашим документом.
надеюсь, что это помогает.!
просто сделал этот кусок кода для добавления (прозрачных) изображений (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");
}
это сработало для меня с 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.сосуд.
@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();
Edit:
Я использую 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.");
как мне не хватало чтобы добавить комментарий, я подумал, что было бы уместно добавить это в новый ответ.
в пакете util есть еще один класс наложения, который избавляет вас от создания pdf с тем же количеством страниц, что и исходный документ, а затем от наложения.
чтобы понять его использование, взгляните на исходный код pdfbox, в частности класс OverlayPDF.
посмотрите на этот метод, whitch добавить изображение водяного знака в источниках 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();
}