Java 基于PDFBox的数字水印
我正试图添加一个水印的PDF专门与PDFBox。我已经能够让图像显示在每个页面上,但它失去了背景透明度,因为它看起来好像PDJpeg将其转换为JPG。也许有一种方法可以使用PDXObjectImage实现 以下是我迄今为止所写的内容:Java 基于PDFBox的数字水印,java,image,pdf,watermark,pdfbox,c#,Java,Image,Pdf,Watermark,Pdfbox,C#,我正试图添加一个水印的PDF专门与PDFBox。我已经能够让图像显示在每个页面上,但它失去了背景透明度,因为它看起来好像PDJpeg将其转换为JPG。也许有一种方法可以使用PDXObjectImage实现 以下是我迄今为止所写的内容: public static void watermarkPDF(PDDocument pdf) throws IOException { // Load watermark BufferedImage buffered = ImageIO.read
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();
}
}
看看这个方法,whitch使用PDFBOX库在pdf源中添加水印图像
/**
* 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();
}
/**
*图像中的颜色与pdf格式中的颜色一致
*
*@param缓冲区
*flujo de bytes que contiene el pdf原件
*
*@param-imageFileName
*科洛卡图像的名称
*
*@param x
*posición x de la imagen en el pdf
*
*@param y
*posición y de la imagen en el pdf
*
*@param-under
*事实的决定权
*
*@return flujo de bytes resultante que contiene el pdf modificado
*
*@抛出异常
*@DocumentException
*/
公共静态字节[]addWaterMarkImageToPDF(字节[]缓冲区,
字符串imageFileName,int x,int y,boolean下)引发IOException,
文档例外{
debug(“Agregando marca de agua:+imageFileName”);
PdfReader读取器=新PdfReader(缓冲区);
ByteArrayOutputStream arrayOutput=新建ByteArrayOutputStream();
OutputStream输出=新的BufferedOutputStream(arrayOutput);
PdfStamper压模=新PdfStamper(读卡器,输出);
com.lowagie.text.Image img=com.lowagie.text.Image
.getInstance(imageFileName);
img.设置绝对位置(x,y);
平均标度百分比(每标度);
PdfContentByte pdfContent;
int total=reader.getNumberOfPages()+1;
对于(int i=1;i
更新的答案(更好的版本,易于添加水印,感谢下面的评论员和@okok提供了答案)
如果您使用的是PDFBox 1.8.10或更高版本,您可以轻松地将水印添加到PDF文档中,从而更好地控制哪些页面需要添加水印。假设您有一个带有水印图像的单页PDF文档,您可以将其覆盖在要添加水印的文档上,如下所示
使用1.8.10的示例代码
旧答案效率低下,不推荐 当OP问到如何在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");
注意:您应该确保两个文档中的页数都匹配。否则,您将得到一个页数与页数最少的文档匹配的文档。您可以操纵水印文档并复制页面以匹配文档
希望这有帮助 刚刚编写了这段代码,用pdfbox将(透明)图像(jpg、png、gif)添加到pdf页面:
/**
* 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();
}
这对我来说适用于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。在util包中有另一个覆盖类,可以避免您创建与源文档相同页数的pdf,然后再进行覆盖
要了解其用法,请查看pdfbox源代码,特别是OverlyPDF类。@Androidman:Addition To 似乎每个版本的PDFBox都删除了许多方法。因此,该代码在PDFBOX2.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(字符串文件名)
,我认为:
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();
由于我没有足够的声誉来添加评论,我认为在新的答案中添加这一点是合适的。这就是我如何在C#中使用PdfBox 2.0.x添加带有日期的文本水印。它将水印置于页面顶部的中心位置
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();
}
}
publicstaticvoidaddwatermark(字符串文件名)
{
StringBuilder sb=新的StringBuilder();
sb.附加(“水印文本”);
sb.Append(DateTime.Now.ToString());
字符串waterMarkText=sb.ToString();
PDDocument origDoc=PDDocument.load(新的java.io.File(文件名));
PDPageTree allPages=origDoc.getPages();
PDFont font=PDType1Font.HELVETICA_粗体;
for(int i=0,len=allPages.getCount();ipublic 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");
}
Overlay overlay = new Overlay();
overlay.setInputPDF(realDoc);
// ** The method setOutputFile(String) is undefined for the type Overlay **
overlay.setOutputFile("final.pdf")
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();
String[] overlayArgs = {"C:/Examples/foreground.pdf", "C:/Examples/background.pdf", "C:/Examples/resulting.pdf"};
OverlayPDF.main(overlayArgs);
System.out.println("Overlay finished.");
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();
}
}
PDDocument realDoc = pdfGenerator.getDocument();
HashMap<Integer, PDDocument> overlayGuide = new HashMap<>();
for (int i = 0; i < realDoc.getNumberOfPages(); i++) {
overlayGuide.put(i + 1, document);
}
Overlay overlay = new Overlay();
overlay.setInputPDF(realDoc);
overlay.setOverlayPosition(Overlay.Position.BACKGROUND);
overlay.overlayDocuments(overlayGuide);