pdf相关工具类(包括docx转pdf,pdf转图片,pdf添加水印)
最近做项目遇到很多关于pdf的一些需求,在整个过程中遇到了很多问题,在这总结一些我遇到的一些问题和一些坑,并且把整理出来并且测试过的工具类发出来,工具类中可能有很多判断没有做,如果有人需要,请自己完善把。
docx转pdf(注意:是docx)
首先注意一下是docx转pdf,本文主要写的是docx转pdf,暂时只支持docx,千万不要尝试doc改个后缀名就可以用了,并不是的,你可以试下,真的不可以,但是也不是说不可以做到doc转pdf,只是转换的时候需要有应用程序,效率上不是很高,而且很麻烦,不如在需求上做个限制,给产品经理买盒烟把。下面还有几个点需要注意一下;
- 更新一下本地的字体库,因为工具是依赖本地的字体库的
- 如果你要上传到服务器上,你要记得把windows下的字体库复制一份到linux下;windows字体在这个路径下: C:\WINDOWS\Fonts, linux下的字体库在这个路径下: /usr/share/fonts;复制好了别忘了敲几行命令把字体生效:
– mkfontscale
– mkfontdir
– fc-cache -fv
pdf转image
- 没什么特别需要注意的,还是字体库,一定要把字体库弄全!尤其是到linux下,一定要字体库复制过去并生效!
pdf添加水印
这个确实有点恶心,这个依赖的jar包是itext2.1.7的jar包,它所引用的水印字体的配置,并不在jar包内,我查了一下资料,才发现,添加水印时候一定要依赖另一个jar包,我觉得像是一个补丁:iTextAsian.jar,我从maven下载了jar包,并引用,发现并没有什么用,我又找了很多资料,发现这个补丁的包结构和itext的结构不一样,需要修改包结构,终于找到问题,修改一下包结构就ok了,后续会把修改后的jar包贴出来,直接下载引用就好,注意一下jar包版本,由于我用的gradle不是maven,所以贴出来的是gradle地址,不过都是一样的,转一下就好;
工具需要的jar包地址
compile group: 'com.lowagie', name: 'itext', version: '2.1.7'
compile fileTree(dir:'libs', include:['*.jar'])
compile 'org.apache.pdfbox:fontbox:2.0.1'
compile 'org.apache.pdfbox:pdfbox:2.0.1'
compile group: 'fr.opensagres.xdocreport', name: 'org.apache.poi.xwpf.converter.pdf', version: '1.0.4'
iTextAsian.jar 下载地址: https://pan.baidu.com/s/1n6SzXd851_BC-LzWH9BQIA
工具类代码
import com.lowagie.text.DocumentException;
import com.lowagie.text.Element;
import com.lowagie.text.pdf.*;
import fr.opensagres.xdocreport.utils.StringUtils;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.rendering.PDFRenderer;
import org.apache.poi.xwpf.converter.pdf.PdfConverter;
import org.apache.poi.xwpf.converter.pdf.PdfOptions;
import org.apache.poi.xwpf.usermodel.*;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @author JiShaochen
* @date 2018/4/14 16:03
* @desc .
*/
public class PDFUtils {
public static void main(String[] args){
// pdfConvertToImage("D:/1.pdf", "D://2");
try {
// docConvertToPdf("D:/1.docx", "D:/2.pdf");
pdfToWatermarkPdf("D:/1.pdf", "D:/3.pdf", "水印文字");
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* @Author: ShaoChen
* @Description: PDF转为多张图片 sourcePath是源文件, targetSource是
* @Date: 16:07 2018/4/14
*/
public static Integer pdfConvertToImage(String sourcePath, String targetSource) {
File file = new File(sourcePath);
try {
file.mkdir();
PDDocument doc = PDDocument.load(file);
PDFRenderer renderer = new PDFRenderer(doc);
int pageCount = doc.getNumberOfPages();
for(int i=0; i<pageCount; i++){
BufferedImage image = renderer.renderImage(i, 2.5f);
ImageIO.write(image,"JPG",new File(targetSource+ "/" + i + ".jpg"));
}
return pageCount;
} catch (IOException e) {
e.printStackTrace();
}
return 0;
}
/**
* @Author: ShaoChen
* @Description: 将docx文件转换为Pdf文件, 调用这个方法,后面的配合使用的
* @Date: 10:30 2018/4/16
*/
public static void docConvertToPdf(String docxPath, String targetUrl) throws Exception {
InputStream source = new FileInputStream(docxPath);
OutputStream target = new FileOutputStream(targetUrl);
Map<String, String> params = new HashMap<String, String>();
PdfOptions options = PdfOptions.create();
wordConverterToPdf(source, target, options, params);
}
/**
* 将word文档, 转换成pdf, 中间替换掉变量
*
* @param source 源为word文档, 必须为docx文档
* @param target 目标输出
* @param params 需要替换的变量
* @throws Exception
*/
public static void wordConverterToPdf(InputStream source,
OutputStream target, Map<String, String> params) throws Exception {
wordConverterToPdf(source, target, null, params);
}
/**
* 将word文档, 转换成pdf, 中间替换掉变量
*
* @param source 源为word文档, 必须为docx文档
* @param target 目标输出
* @param params 需要替换的变量
* @param options PdfOptions.create().fontEncoding( "windows-1250" ) 或者其他
* @throws Exception
*/
public static void wordConverterToPdf(InputStream source, OutputStream target,
PdfOptions options,
Map<String, String> params) throws Exception {
XWPFDocument doc = new XWPFDocument(source);
paragraphReplace(doc.getParagraphs(), params);
for (XWPFTable table : doc.getTables()) {
for (XWPFTableRow row : table.getRows()) {
for (XWPFTableCell cell : row.getTableCells()) {
paragraphReplace(cell.getParagraphs(), params);
}
}
}
PdfConverter.getInstance().convert(doc, target, options);
}
/**
* 替换段落中内容
*/
private static void paragraphReplace(List<XWPFParagraph> paragraphs, Map<String, String> params) {
if (!params.isEmpty()) {
for (XWPFParagraph p : paragraphs) {
for (XWPFRun r : p.getRuns()) {
String content = r.getText(r.getTextPosition());
if (StringUtils.isNotEmpty(content) && params.containsKey(content)) {
r.setText(params.get(content), 0);
}
}
}
}
}
/**
* @Author: ShaoChen
* @Description: pdf添加水印
* @Date: 10:36 2018/4/16
*/
public static void pdfToWatermarkPdf(String sourceUrl, String targetUrl, String message) throws IOException, DocumentException {
// 要输出的pdf文件
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(new File(targetUrl)));
// 将pdf文件先加水印然后输出
setWatermark(bos, sourceUrl, 16, message);
}
public static void setWatermark(BufferedOutputStream bos, String input,
int permission, String message) throws DocumentException,
IOException {
PdfReader reader = new PdfReader(input);
PdfStamper stamper = new PdfStamper(reader, bos);
int total = reader.getNumberOfPages() + 1;
BaseFont base = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H",BaseFont.EMBEDDED);
PdfGState gs = new PdfGState();
for (int i = 1; i < total; i++) {
/*
首先介绍一下: 前两个参数是pdf的横纵坐标,可以想象成一个平面直角坐标系,原地在pdf每页的左下角;
line为x轴;
height为y轴;
angle为水印的角度;
这三个参数自己调整就好
*/
// 设置第一行水印
setLineWaterMark(stamper, base, gs, i, 140,1000, 40, message);
setLineWaterMark(stamper, base, gs, i, 320,1000, 40, message);
setLineWaterMark(stamper, base, gs, i, 500,1000, 40, message);
setLineWaterMark(stamper, base, gs, i, 680,1000, 40, message);
setLineWaterMark(stamper, base, gs, i, 860,1000, 40, message);
// 设置第二行水印
setLineWaterMark(stamper, base, gs, i, 140,700, 40, message);
setLineWaterMark(stamper, base, gs, i, 320,700, 40, message);
setLineWaterMark(stamper, base, gs, i, 500,700, 40, message);
setLineWaterMark(stamper, base, gs, i, 680,700, 40, message);
setLineWaterMark(stamper, base, gs, i, 860,700, 40, message);
// 设置第三行水印
setLineWaterMark(stamper, base, gs, i, 140,400, 40, message);
setLineWaterMark(stamper, base, gs, i, 320,400, 40, message);
setLineWaterMark(stamper, base, gs, i, 500,400, 40, message);
setLineWaterMark(stamper, base, gs, i, 680,400, 40, message);
setLineWaterMark(stamper, base, gs, i, 860,400, 40, message);
// 设置第四行水印
setLineWaterMark(stamper, base, gs, i, 140,100, 40, message);
setLineWaterMark(stamper, base, gs, i, 320,100, 40, message);
setLineWaterMark(stamper, base, gs, i, 500,100, 40, message);
setLineWaterMark(stamper, base, gs, i, 680,100, 40, message);
setLineWaterMark(stamper, base, gs, i, 860,100, 40, message);
}
stamper.close();
}
private static void setLineWaterMark(PdfStamper stamper, BaseFont base, PdfGState gs, int page, Integer line,
Integer height, Integer angle, String message) {
PdfContentByte content;
content = stamper.getOverContent(page);// 在内容上方加水印
// content = stamper.getUnderContent(i);//在内容下方加水印
gs.setFillOpacity(0.2f);
content.setGState(gs);
content.beginText();
content.setColorFill(Color.LIGHT_GRAY);
content.setFontAndSize(base, 16);
content.setTextMatrix(20, 70);
content.showTextAligned(Element.ALIGN_CENTER, message, line, height, angle);
content.setColorFill(Color.BLACK);
content.setFontAndSize(base, 8);
content.endText();
}
}