一、设计思路
二、准备工作
1、linux安装中文字体文件
1)准备字体文件
找到windows系统的字体文件夹:C:\Windows\Fonts
可以看到有很多字体文件,不需要全部使用,只需要中文的即可,根据需要选取
2)linux字体文件安装
cd /usr/share/fonts/ #进入字体目录 mkdir chinese #将windows系统中的字体文件上传到linux系统该文件夹中 chmod 755 /usr/share/fonts/chinese/* #更改字体权限 cd /usr/share/fonts/chinese #进入字体目录 mkfontscale #(若提示“mkfontscale command not found",则运行 yum install mkfontscale) mkfontdir #(若提示“Couldn't determine full name for xxx.fon,则删除与之对应的文件) fc-cache
2、添加maven依赖
<!-- PDF添加水印依赖 --> <dependency> <groupId>com.itextpdf</groupId> <artifactId>itextpdf</artifactId> <version>5.5.5</version> </dependency> <dependency> <groupId>com.itextpdf</groupId> <artifactId>itext-asian</artifactId> <version>5.2.0</version> </dependency> <!-- PDF操作工具包 --> <dependency> <groupId>org.apache.pdfbox</groupId> <artifactId>pdfbox-app</artifactId> <version>2.0.16</version> </dependency>
三、开发流程
1、获取原始pdf文件
方法:File file = new File("文件路径");
2、获取原始pdf文件byte数组
方法:handleReadData
3、原始pdf文件添加水印
方法:pdfAddWaterMark
4、添加水印的pdf文件转图片
方法:pdfToImage,默认转为png格式,可手动修改(代码189行),返回pdf图片集合
5、创建空白pdf文件
方法:createBlankPdf
6、pdf图片集合转为新的pdf
方法:fillImg2Pdf,将pdf图片集合添加到创建的空白pdf文档内
7、删除文件(可选)
方法:delFolder(删除文件夹)、delAllFile(删除指定文件夹下所有文件)
四、完整代码
package com.hylink.utils;
import com.itextpdf.text.BaseColor;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Element;
import com.itextpdf.text.pdf.*;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDDocumentInformation;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;
import org.apache.pdfbox.rendering.PDFRenderer;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.*;
public class PDFUtil {
//服务器字体文件路径
// public static final String fontsPath = "/static/fonts/STCAIYUN.TTF";
public static final String fontsPath = "C:\\Windows\\Fonts\\STCAIYUN.TTF";
public static void main(String[] args) throws Exception {
File file = new File("C:\\Users\\Administrator\\Desktop\\demo\\耕地承包申请书.pdf");
byte[] bytes = handleReadData(file);
String fileName = UUID.randomUUID() + ".pdf";
String saveFilePath = "C:\\Users\\Administrator\\Desktop\\demo";
pdfAddWaterMark(bytes, "仅用于办理土地承包申请", fileName, saveFilePath, 2);
// List<File> files = pdfToImage("C:\\Users\\Administrator\\Desktop\\demo\\690146b1-f169-4d9c-906f-695aa32b556c.pdf", "C:\\Users\\Administrator\\Desktop\\demo", 144);
// File targetFile = new File("C:\\Users\\Administrator\\Desktop\\demo\\1.pdf");
// createBlankPdf(targetFile, files.size());
// fillImg2Pdf(targetFile, files);
}
public static byte[] handleReadData(File file) {
try {
FileInputStream in = new FileInputStream(file);
ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
byte[] tmpBuffer = new byte[(2 << 9) * 1];
int count;
while ((count = in.read(tmpBuffer)) != -1) {
byteOut.write(tmpBuffer, 0, count);
tmpBuffer = new byte[(2 << 9) * 1];
}
in.close();
return byteOut.toByteArray();
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* PDF文件转PNG图片,全部页数
*
* @param PdfFilePath pdf完整路径
* @param dstImgFolder 图片存放的文件夹
* @param dpi dpi越大转换后越清晰,相对转换速度越慢
* @return 返回转换后图片集合list
*/
public static List<File> pdfToImage(String PdfFilePath, String dstImgFolder, int dpi) {
UUID uuid = UUID.randomUUID();
String uuId = uuid.toString();
System.out.println(uuId);
File file = new File(PdfFilePath);
//定义集合保存返回图片数据
List<File> fileList = new ArrayList<File>();
@SuppressWarnings("resource")//抑制警告
PDDocument pdDocument = new PDDocument();
try {
//String imagePDFName = file.getName().substring(0, dot); // 获取图片文件名
String imgFolderPath = null;
if (dstImgFolder.equals("")) {
imgFolderPath = dstImgFolder + File.separator + uuId;// 获取图片存放的文件夹路径
} else {
imgFolderPath = dstImgFolder + File.separator + uuId;
}
if (createDirectory(imgFolderPath)) {
pdDocument = PDDocument.load(file);
PDFRenderer renderer = new PDFRenderer(pdDocument);
/* dpi越大转换后越清晰,相对转换速度越慢 */
PdfReader reader = new PdfReader(PdfFilePath);
int pages = reader.getNumberOfPages();
System.out.println("pdf总共多少页-----" + pages);
StringBuffer imgFilePath = null;
for (int i = 0; i < pages; i++) {
String imgFilePathPrefix = imgFolderPath + File.separator + "pdf";
System.out.println("imgFilePathPrefix=====" + imgFilePathPrefix);
imgFilePath = new StringBuffer();
imgFilePath.append(imgFilePathPrefix);
imgFilePath.append("-");
imgFilePath.append(i);
imgFilePath.append(".png");
File dstFile = new File(imgFilePath.toString());
BufferedImage image = renderer.renderImageWithDPI(i, dpi);
ImageIO.write(image, "png", dstFile);
fileList.add(dstFile);
}
System.out.println("PDF文档转PNG图片成功!");
return fileList;
} else {
System.out.println("PDF文档转PNG图片失败:" + "创建" + imgFolderPath + "失败");
return null;
}
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
/**
* pdf 加水印
*
* @param byes 待加水印文件字节数组
* @param waterMarkStr 水印字符串
* @param fileName 最终文件名称
* @param saveFilePath 保存地址
* @param number 每页水印条数
*/
public static void pdfAddWaterMark(byte[] byes, String waterMarkStr, String fileName, String saveFilePath, int number) {
String courseFile = "";
try {
//生成临时文件 , 读取完删除
File directory = new File(saveFilePath);
courseFile = directory.getCanonicalPath() + "/";
} catch (IOException e) {
e.printStackTrace();
}
// 待加水印的文件
PdfReader reader = null;
PdfStamper stamper = null;
FileOutputStream os = null;
try {
reader = new PdfReader(byes);
// 加完水印的文件
os = new FileOutputStream(courseFile + fileName);
stamper = new PdfStamper(reader, os);
int total = reader.getNumberOfPages() + 1;
PdfContentByte content;
// 字体库字体
// BaseFont basefont = BaseFont.createFont(fontsPath, BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
//这里的字体设置比较关键,这个设置是支持中文的写法 使用系统字体
BaseFont basefont = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
PdfContentByte under;
com.itextpdf.text.Rectangle pageRect = null;
// 循环对每页插入水印
for (int i = 1; i < total; i++) {
pageRect = stamper.getReader().getPageSizeWithRotation(i);
// 计算水印X,Y坐标
float x = (float) (pageRect.getWidth() / 1.98);
float y = (float) (pageRect.getHeight() / 2.8);
// 获得PDF最顶层
under = stamper.getOverContent(i);
under.saveState();
under.restoreState();
under.beginText();
// set Transparency
PdfGState gs = new PdfGState();
// 设置透明度为0.2
gs.setFillOpacity(0.3f);
under.setGState(gs);
// 水印字体和大小
under.setFontAndSize(basefont, pageRect.getHeight() / 17);
// 水印颜色
under.setColorFill(BaseColor.RED);
// 水印文字成45度角倾斜
for (int j = 0; j < number; j++) {
under.showTextAligned(Element.ALIGN_CENTER, waterMarkStr, x, y * (j + 1), 45);
}
// 添加水印文字
under.endText();
under.setLineWidth(1f);
under.stroke();
}
} catch (IOException e) {
e.printStackTrace();
} catch (DocumentException e) {
e.printStackTrace();
} finally {
try {
stamper.close();
if (os != null) {
os.close();
}
if (reader != null) {
reader.close();
}
} catch (DocumentException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
//创建文件夹
private static boolean createDirectory(String folder) {
File dir = new File(folder);
if (dir.exists()) {
return true;
} else {
return dir.mkdirs();
}
}
//删除文件夹
//param folderPath 文件夹完整绝对路径
public static void delFolder(String folderPath) {
try {
delAllFile(folderPath); //删除完里面所有内容
String filePath = folderPath;
filePath = filePath;
File myFilePath = new File(filePath);
myFilePath.delete(); //删除空文件夹
} catch (Exception e) {
e.printStackTrace();
}
}
//删除指定文件夹下所有文件
//param path 文件夹完整绝对路径
public static boolean delAllFile(String path) {
boolean flag = false;
File file = new File(path);
if (!file.exists()) {
return flag;
}
if (!file.isDirectory()) {
return flag;
}
String[] tempList = file.list();
File temp = null;
for (int i = 0; i < tempList.length; i++) {
if (path.endsWith(File.separator)) {
temp = new File(path + tempList[i]);
} else {
temp = new File(path + File.separator + tempList[i]);
}
if (temp.isFile()) {
temp.delete();
}
if (temp.isDirectory()) {
delAllFile(path + "/" + tempList[i]);//先删除文件夹里面的文件
delFolder(path + "/" + tempList[i]);//再删除空文件夹
flag = true;
}
}
return flag;
}
/**
* 创建空白PDF文档
*
* @param pageNum
*/
public static void createBlankPdf(File targetFile, int pageNum) {
// 创建文档
PDDocument pdDocument = new PDDocument();
// 设置文档属性
createMainInformation(pdDocument);
for (int i = 0; i < pageNum; i++) {
// 创建页码
PDPage blankPage = new PDPage();
// 添加到文档
pdDocument.addPage(blankPage);
}
try {
// 保存文档
pdDocument.save(targetFile);
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
// 关闭文档
pdDocument.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 设置文档属性
*
* @param pdDocument
*/
public static void createMainInformation(PDDocument pdDocument) {
PDDocumentInformation pdd = pdDocument.getDocumentInformation();
pdd.setAuthor("章三");
pdd.setTitle("图片转换PDF");
pdd.setCreator("PDF Examples");
pdd.setSubject("主题哦");
Calendar date = new GregorianCalendar();
date.set(2019, 11, 6);
pdd.setCreationDate(date);
date.set(2019, 11, 7);
pdd.setModificationDate(date);
pdd.setKeywords("hi, my pdf!");
}
/**
* 填充图片到PDF文件
*/
public static void fillImg2Pdf(File targetFile, List<File> imgFileList) {
// 加载现有文档
PDDocument doc = null;
try {
doc = PDDocument.load(targetFile);
for (int i = 0; i < imgFileList.size(); i++) {
File imgFile = imgFileList.get(i);
// 获取文档页面
PDPage page = doc.getPage(i);
PDImageXObject pdImage = PDImageXObject.createFromFile(imgFile.getPath(), doc);
PDPageContentStream contents = new PDPageContentStream(doc, page);
Map<String, Float> sizeMap = getSize(imgFile, page, 30, 30);
contents.drawImage(pdImage, sizeMap.get("x"), sizeMap.get("y"), sizeMap.get("width"), sizeMap.get("height"));
contents.close();
}
doc.save(targetFile);
} catch (IOException e) {
e.printStackTrace();
} finally {
if (doc != null) {
try {
doc.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
/**
* @param imgFile 图片文件
* @param page PDF页
* @param paddW 横向内边距
* @param paddH 纵向内边距
* @return
*/
private static Map<String, Float> getSize(File imgFile, PDPage page, float paddW, float paddH) {
Map<String, Float> map = new HashMap<String, Float>();
BufferedImage bufferedImage;
try {
bufferedImage = ImageIO.read(imgFile);
float pageW = page.getBBox().getWidth() - paddW * 2;// 文档真实宽
float pageH = page.getBBox().getHeight() - paddH * 2;// 文档真实高
float imageW = bufferedImage.getWidth();
float imageH = bufferedImage.getHeight();
float scale = resize(bufferedImage, pageW, pageH);// 缩放比例
// 获取位置
// 文档横坐标
map.put("x", paddW + (pageW - imageW * scale) / 2);
// 文档纵坐标
map.put("y", pageH - imageH * scale + paddH);
// 图片缩放后宽度
map.put("width", imageW * scale);
// 图片缩放后高度
map.put("height", imageH * scale);
} catch (IOException e) {
e.printStackTrace();
}
return map;
}
/**
* 获取图片缩放比例
*
* @param imgFile
* @param pageW
* @param pageH
* @return
*/
private static float resize(File imgFile, float pageW, float pageH) {
BufferedImage bufferedImage;
try {
bufferedImage = ImageIO.read(imgFile);
float width = bufferedImage.getWidth();
float height = bufferedImage.getHeight();
float scale = 1f;
// 宽高都小于PDF,原样输出
if (width <= pageW && height <= pageH) {
return scale;
}
// 宽和高都大于PDF
if (width > pageW && height > pageH) {
return pageW / width < pageH / height ? pageW / width : pageH / height;
}
// 宽和高其一大于PDF
return width > pageW ? pageW / width : pageH / height;
} catch (IOException e) {
e.printStackTrace();
}
return 1;
}
/**
* 获取图片缩放比例
*
* @param bufferedImage
* @param pageW
* @param pageH
* @return
*/
private static float resize(BufferedImage bufferedImage, float pageW, float pageH) {
float width = bufferedImage.getWidth();
float height = bufferedImage.getHeight();
float scale = 1f;
// 宽高都小于PDF,原样输出
if (width <= pageW && height <= pageH) {
return scale;
}
// 宽和高都大于PDF
if (width > pageW && height > pageH) {
return pageW / width < pageH / height ? pageW / width : pageH / height;
}
// 宽和高其一大于PDF
return width > pageW ? pageW / width : pageH / height;
}
}