以前写了一个pdf添加图片水印的工具类, 现在在写一个对上传的pdf文件添加文字水印的例子。效果如下
这个工具类需要依赖两个架包,可以网上下载。(其实主要依赖第一个,但是用到的字体样式需要依赖第二个,不然会报错)
itextpdf-5.5.6.jar
itext-asian-5.2.0.jar
后台主要处理代码工具类 uploadPdfAndMarkUtils.java
package uploadPdfTest;
import java.awt.FontMetrics;
/**
* 上传pdf添加文案水印
*
* @author yulisao
* @createDate 2020年7月16日
*/
public class uploadPdfAndMarkUtils {
private static int interval = -5;
private static final String markText = "这是pdf水印文案内容"; // 可以写死也可以写配置文件里面
private static Logger logger = Logger.getLogger(Object.class);
/**
* 对上传的pdf进行大小判定,并添加水印
*
* 注:
* 1.输入与输出路径均是路径+文件,如:/home/123.pdf
* 2.输出路径不可与输入路径完全一致,很严重!
*
* @param filePath pdf长传文件路径
* @param outPath pdf输出路径(包含文件名称)
* @param pdfnum 限制最大pdf页数
*/
public static void markPdf(String filePath, String outPath, int pdfnum) {
int filnum=getPdfFilePageNum(filePath); // 获取页数
logger.info("上传pdf文件页数:" + filnum);
if(filnum > pdfnum){
logger.info("pdf页数超出,请重新上传页数不大于"+ pdfnum +"页的pdf文件");
return;
}
File filePdf= new File(filePath);
long fildSize=filePdf.length();
long tran_file_size= fildSize/1024; // pdf的实际大小
long limitSize = 256*pdfnum; // 限制pdf的最大大小, 单页最大256k
if( tran_file_size > limitSize ){
logger.info("文件大小不能超过"+limitSize+"KB");
return;
}
// 添加水印
try {
PdfReader reader = new PdfReader(filePath);
PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(
outPath));
BaseFont base = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.EMBEDDED);
Rectangle pageRect = null;
// 设置水印透明度
PdfGState gs = new PdfGState();
gs.setFillOpacity(0.3f);
gs.setStrokeOpacity(0.4f);
int total = reader.getNumberOfPages() + 1;
JLabel label = new JLabel();
FontMetrics metrics;
int textH = 0;
int textW = 0;
label.setText(markText);
metrics = label.getFontMetrics(label.getFont());
textH = metrics.getHeight();
textW = metrics.stringWidth(label.getText());
PdfContentByte under;
for (int i = 1; i < total; i++) {
pageRect = reader.getPageSizeWithRotation(i);
under = stamper.getOverContent(i);//在内容上方添加水印
under.saveState();
under.setGState(gs);
// 设置字体和字体大小
under.beginText();
under.setFontAndSize(base, 20);
under.setTextMatrix(70, 200);
// 水印文字成30度角倾斜展示多个
for (int height = interval + textH; height < pageRect.getHeight();height = height + textH*4) {
for (int width = interval + textW; width < pageRect.getWidth() + textW;width = width + textW*2) {
under.showTextAligned(Element.ALIGN_LEFT, markText, width - textW,height - textH, 30);
}
}
// 添加水印文字
under.endText();
}
stamper.close();
reader.close();
filePdf.delete(); // 原文件不需要的话可以删掉,节约空间
} catch (Exception e) {
logger.error(e.getMessage());
e.printStackTrace();
}
}
/**
* 获取pdf页数
*
* @param filePath 文件路径
* @return int
*/
private static int getPdfFilePageNum(String filePath) {
int pageNumber=0;
PdfReader pdfReader;
try{
pdfReader = new PdfReader(new FileInputStream(filePath));
pageNumber = pdfReader.getNumberOfPages();
}catch (Exception e){
logger.info("获取上传文件的页数失败");
e.printStackTrace();
}
return pageNumber ;
}
}
自测 测试类
package uploadPdfTest;
/**
* 测试类
*
*
* @author yulisao
* @createDate 2020年07月16日
*/
public class Testmain {
public static void main(String[] args) {
String filePath = "C://Users//Administrator//Desktop//qrtest//file.pdf" ;
String outPath = "C://Users//Administrator//Desktop//qrtest//marked.pdf" ;
int pdfnum = 10 ;
uploadPdfAndMarkUtils.markPdf(filePath, outPath, pdfnum);
}
}
以下是项目中的页面上的一些代码,需要的可以参考参考。
1.html长传代码。 bootstrap框架,样式文件和js库 自行引入。
<style>
.file {
position: relative;
display: inline-block;
background: #D0EEFF;
border: 1px solid #99D3F5;
border-radius: 4px;
padding: 4px 12px;
overflow: hidden;
color: #1E88C7;
text-decoration: none;
text-indent: 0;
line-height: 20px;
}
.file input {
position: absolute;
font-size: 100px;
right: 0;
top: 0;
opacity: 0;
}
.file:hover {
background: #AADFFD;
border-color: #78C3F3;
color: #004974;
text-decoration: none;
}
.pdf-span {
color:#ff0000;
margin-left:5px;
margin-botton:40px;
}
</style>
<div class="form-group">
<label for="pdf_uploadPdf1" class="col-lg-2 col-sm-2 control-label">请上传pdf1:</label>
<div class="col-lg-3">
<input type="hidden" id="pdf_uploadPdf1" name="form_pdf1" />
<input type="hidden" id="page_uploadPdf1" value="1" />
<a href="javascript:;" class="file" >上传
<input type="file" onchange="uploadFile(this)" accept="*.pdf" id="uploadPdf1" />
</a>
<span class="pdf-span">PDF 格式,单页 256K 字节,最大1页面</span>
</div>
<label for="pdf_uploadPdf2" class="col-lg-2 col-sm-2 control-label">请上传pdf2:</label>
<div class="col-lg-3">
<input type="hidden" id="pdf_uploadPdf2" name="form_pdf2" />
<input type="hidden" id="page_uploadPdf2" value="5" />
<a href="javascript:;" class="file" >上传
<input type="file" onchange="uploadFile(this)" accept="*.pdf" id="uploadPdf2" />
</a>
<span class="pdf-span">PDF 格式,单页 256K 字节,最大5页面</span>
</div>
</div>
js 代码
function uploadFile(input) {
var fileName = uuid()+'.pdf'; // 随机生成新的文件名
var vale = "pdf_"+input.id; // pdf隐藏的input的id,用于存pdf的上传路径
var pdfnum = $("#page_" +input.id ).val(); //获取pdf允许最大页数
var formData = new FormData();
var group = input.dataset.group;
var pdf_size = $('#' + input.id)[0].files[0];
var aginput = '<input type="file" onchange="uploadFile(this)" accept="*.pdf" id="'+input.id+'" />'; // 上传按钮的input标签,用于解决上传一次后无法再次上次
// 校验文件后缀格式
if (!pdf_size.name.match(/.pdf/i)) {
Messenger().post("非pdf文件,请重新选择!");
$('#' + input.id).replaceWith(aginput); // 成功或者失败都覆盖一下才能再次上次
return false;
}
// 校验文件大小
var lmtSize = 256*pdfnum ; // 默认每页最大256k
if (pdf_size.size / 1024 > lmtSize){
Messenger().post("文件最大"+lmtSize+"k,请重新选择上传");
$('#' + input.id).replaceWith(aginput);
return false;
}
formData.append('file', $('#' + input.id)[0].files[0]);
var filePath = "/tempfiles"; // 服务器临时存储路径
$.ajax({
url: "127.0.0.1/common/fileUpload.jsp?FileName=tmp" + fileName + "&FolderName=" + filePath,
type: "POST",
cache: false,
data: formData,
processData: false,
contentType: false
}).success(function(res){ // 上传成功
checkFileAndAddMark("tempfiles/", fileName, pdfnum, vale);
$('#' + input.id).replaceWith(aginput);
}
).fail(function(res){
Messenger().post("上传失败");
$('#' + input.id).replaceWith(aginput);
});
}
// 添加水印
function checkFileAndAddMark(filePath, fileName, pdfnum, vale){
$.ajax({
url : "127.0.0.1/fileutils/checkFileAndAddMark.do",
type : "POST",
data : {
filePath: filePath + "tmp" + fileName,
pdfnum: pdfnum
},
dataType : "json",
success : function(res) {
if (res.code == '1') {
Messenger().post("上传成功");
$('#' + vale).val(filePath + fileName); //上传成功并加好水印的存储路径给页面上隐藏的input
} else {
Messenger().post({
singleton : true,
message : "上传失败,"+res.msg+"!"
});
}
},
error : function(res) {
Messenger().post({
singleton : true,
message : "上传失败,"+res.msg+"!"
});
}
});
return false;
}
function uuid() {
var s = [];
var hexDigits = "0123456789abcdef";
for (var i = 0; i < 36; i++) {
s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1);
}
s[14] = "4"; // 12-15bit
s[19] = hexDigits.substr((s[19] & 0x3) | 0x8, 1); // 6-7bit
s[8] = s[13] = s[18] = s[23] = "-";
var uuid = s.join("");
return uuid;
}
- 上传按钮有一个小问题, 上传过一次后,若想点击按钮重新选择一个pdf上传会发现点击按钮无反应。所以js里面定义了一个aginput ,原理就是把页面上的input标签重新覆盖一下可以解决这个问题。 查了网上说因为第一次上传后input就有值了,所以再次点击就没反应了。重新覆盖一下就相当于清除了value。所以还有一种方法: 把上传按钮的那个input 的value置空,有兴趣的话可以尝试一下这个方案,咱就没去考证了。
- 传到后台的文件名是随机生的uuid加上前缀tmp,经过后台处理加水印后的pdf文件名就是uuid,不喜欢这样偷懒的话可以在后台重新生成一个文件名再返回到页面上来也可以。
fileUpload.jsp 也提供参考
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ page import="net.sf.json.JSONArray"%>
<%@ page import="net.sf.json.JSONObject"%>
<%@ page import="org.apache.commons.fileupload.*"%>
<%@ page import="org.apache.commons.fileupload.servlet.*"%>
<%@ page import="org.apache.commons.fileupload.disk.*"%>
<%@ page import="java.util.*"%>
<%@ page import="java.io.*"%>
<%@ page import="javax.servlet.http.HttpServletRequest"%>
<%
String FolderName= request.getParameter("FolderName"); // 长传文件指定的目录
String file_name=request.getParameter("FileName"); // 文件名
String userHome = System.getProperty("user.home"); // 服务器根目录
String rootPath=userHome+FolderName;
out.print(rootPath);
boolean isMultipart = ServletFileUpload.isMultipartContent(request);
JSONObject obj = new JSONObject();
JSONObject result = new JSONObject();
if (isMultipart == true) {
try {
FileItemFactory factory = new DiskFileItemFactory();
ServletFileUpload upload = new ServletFileUpload(factory);
upload.setHeaderEncoding("utf-8");
List<FileItem> items = upload.parseRequest(request);
Iterator<FileItem> itr = items.iterator();
String uploadPath, filePath;
JSONArray fileJsonArray = new JSONArray();
JSONObject fileJson;
while (itr.hasNext()) {
FileItem item = (FileItem) itr.next();
String fileName = item.getName();
if (fileName != null) {
uploadPath = rootPath;
File file = new File(uploadPath);
if (!file.exists()) {
file.mkdir();
}
File fullFile;
if(file_name!=null && file_name.length()!=0){
fullFile = new File(file_name);
}else{
fullFile = new File(item.getName());
}
filePath = uploadPath + File.separator
+ fullFile.getName();
fileJson = new JSONObject();
fileJson.put("filePath", filePath);
fileJsonArray.add(fileJson);
File savedFile = new File(filePath);
item.write(savedFile);
}
}
obj.put("msgType", "1");
obj.put("msgCode", "1");
obj.put("msgInfo", "上传成功!");
result.put("obj", obj);
result.put("file", fileJsonArray);
out.println(result.toString());
} catch (Exception e) {
obj.put("msgType", "-1");
obj.put("msgCode", "-1");
obj.put("msgInfo", "上传失败! " + e.getMessage());
result.put("obj", obj);
out.println(result.toString());
}
} else {
obj.put("msgType", "-2");
obj.put("msgCode", "-2");
obj.put("msgInfo", "上传失败! 请选择一个文件");
result.put("obj", obj);
out.println(result.toString());
}
%>