最近接到个需求,根据所传关键字,定位关键字所在pdf文件中的坐标,然后盖章,其中所传参数还有关键字所在页数,和获取第几次出现的关键字,会传多个印章和关键字,每个印章对应一个关键字。自己先写了个简单demo,和大家共享,还请多多指正。
package test.ne2.bean;
public class KeyWordBean implements Comparable {
public KeyWordBean() {
super();
}
public KeyWordBean(float x, float y, int page, String text) {
super();
this.x = x;
this.y = y;
this.page = page;
this.text = text;
}
private float x;
private float y;
private int page;
private String text;
public float getX() {
return x;
}
public void setX(float x) {
this.x = x;
}
public float getY() {
return y;
}
public void setY(float y) {
this.y = y;
}
public int getPage() {
return page;
}
public void setPage(int page) {
this.page = page;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
@Override
public String toString() {
return "KeyWordBean [x=" + x + ", y=" + y + ", page=" + page
+ ", text=" + text + "]";
}
@Override
public int compareTo(KeyWordBean o) {
int i = (int) (o.getY() - this.getY());//先按照Y轴排序
if(i == 0){
return (int) (this.x - o.getX());//如果Y轴相等了再按X轴进行排序
}
return i;
}
}
package test.ne2.bean;
public class SignPDFBean {
private String keyWord; // 签章关键字
private int page; // 关键字所在页数
private int num; // 取第n次出现的关键字
private String sealPath; // 印章图片路径
private String keyStorePath; // 证书文件路径
private String keyStorePass; // 证书密码
private String signReason; // 设置签章原因,可以为空
private String signLocation; // 设置签章地点
public String getKeyWord() {
return keyWord;
}
public void setKeyWord(String keyWord) {
this.keyWord = keyWord;
}
public int getPage() {
return page;
}
public void setPage(int page) {
this.page = page;
}
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
public String getSealPath() {
return sealPath;
}
public void setSealPath(String sealPath) {
this.sealPath = sealPath;
}
public String getKeyStorePath() {
return keyStorePath;
}
public void setKeyStorePath(String keyStorePath) {
this.keyStorePath = keyStorePath;
}
public String getKeyStorePass() {
return keyStorePass;
}
public void setKeyStorePass(String keyStorePass) {
this.keyStorePass = keyStorePass;
}
public String getSignReason() {
return signReason;
}
public void setSignReason(String signReason) {
this.signReason = signReason;
}
public String getSignLocation() {
return signLocation;
}
public void setSignLocation(String signLocation) {
this.signLocation = signLocation;
}
@Override
public String toString() {
return "SignPDFBean [keyWord=" + keyWord + ", page=" + page + ", num="
+ num + ", sealPath=" + sealPath + ", keyStorePath="
+ keyStorePath + ", keyStorePass=" + keyStorePass
+ ", signReason=" + signReason + ", signLocation="
+ signLocation + "]";
}
}
package test.ne2.bean;
import java.util.List;
public class SignPDFRequestBean {
private String srcPDFPath; // 待签章pdf文件路径
private String outPDFPath; // 签章后输出的pdf文件路径
private List SignPDFBeans;
public String getSrcPDFPath() {
return srcPDFPath;
}
public void setSrcPDFPath(String srcPDFPath) {
this.srcPDFPath = srcPDFPath;
}
public String getOutPDFPath() {
return outPDFPath;
}
public void setOutPDFPath(String outPDFPath) {
this.outPDFPath = outPDFPath;
}
public List getSignPDFBeans() {
return SignPDFBeans;
}
public void setSignPDFBeans(List signPDFBeans) {
SignPDFBeans = signPDFBeans;
}
@Override
public String toString() {
return "SignPDFRequestBean [srcPDFPath=" + srcPDFPath + ", outPDFPath="
+ outPDFPath + ", SignPDFBeans=" + SignPDFBeans + "]";
}
}
package test.ne2;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang.StringUtils;
import test.ne2.bean.KeyWordBean;
import com.google.common.collect.Lists;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.parser.ImageRenderInfo;
import com.itextpdf.text.pdf.parser.PdfReaderContentParser;
import com.itextpdf.text.pdf.parser.RenderListener;
import com.itextpdf.text.pdf.parser.TextRenderInfo;
public class KeywordPDFUtils {
// 定义返回页码
private static int i = 0;
private static com.itextpdf.awt.geom.Rectangle2D.Float boundingRectange =null;
private static List lists = null;
// private static KeyWordBean bean = new KeyWordBean();
private static Map> map = new HashMap>();
public static Map> getPDFText(String filePath) {
try {
PdfReader pdfReader = new PdfReader(filePath);
int pageNum = pdfReader.getNumberOfPages();
PdfReaderContentParser pdfReaderContentParser = new PdfReaderContentParser(pdfReader);
for (i = 1; i <= pageNum; i++) {
lists = Lists.newArrayList();
boundingRectange =new com.itextpdf.awt.geom.Rectangle2D.Float();
pdfReaderContentParser.processContent(i, new RenderListener() {
@Override
public void renderText(TextRenderInfo textRenderInfo) {
String text = textRenderInfo.getText(); // 整页内容
boundingRectange= textRenderInfo.getBaseline().getBoundingRectange();
KeyWordBean bean = new KeyWordBean();
bean.setX(boundingRectange.x);
bean.setY(boundingRectange.y);
bean.setPage(i);
bean.setText(text);
lists.add(bean);
}
@Override
public void renderImage(ImageRenderInfo arg0) {
// TODO Auto-generated method stub
}
@Override
public void endTextBlock() {
// TODO Auto-generated method stub
}
@Override
public void beginTextBlock() {
// TODO Auto-generated method stub
}
});
map.put(i, lists);
}
} catch (IOException e) {
e.printStackTrace();
}
return map;
}
public static void main(String[] args) {
Map> keyWords = getPDFText("D:\\pdf\\src.pdf");
System.out.println(keyWords.size());
}
public static KeyWordBean getKeyWordXY(Map> map2, int page, int num,String keyWord) {
int keyMatch = 1;
StringBuilder content = new StringBuilder();
List list = map.get(page);
Collections.sort(list);//正序比较
StringBuilder builder = new StringBuilder();
for(int i=0; i0){
content.append(text);
if(content.length() >= keyWord.length()){
if(StringUtils.contains(content.toString(), keyWord)){
if(keyMatch == num){
return bean;
}else{
keyMatch ++;
}
}
content = new StringBuilder();
}
}
}
}else{
if (StringUtils.contains(content.toString(), keyWord) || StringUtils.contains(text, keyWord)) {
if(keyMatch == num){
return bean;
}else{
keyMatch ++;
}
}else if((!StringUtils.isEmpty(text) && keyWord.startsWith(text)) || content.length()>0){
content.append(text);
if(content.length() >= keyWord.length()){
if(StringUtils.contains(content.toString(), keyWord)){
if(keyMatch == num){
return bean;
}else{
keyMatch ++;
}
}
content = new StringBuilder();
}
}
}
}
return null;
}
public static KeyWordBean getKeyWordBean(KeyWordBean bean, StringBuilder content, String keyWord, String text, int keyMatch, int num){
if (StringUtils.contains(content.toString(), keyWord) || StringUtils.contains(text, keyWord)) {
if(keyMatch == num){
return bean;
}else{
keyMatch ++;
}
}else if((!StringUtils.isEmpty(text) && keyWord.startsWith(text)) || content.length()>0){
content.append(text);
if(content.length() >= keyWord.length()){
if(StringUtils.contains(content.toString(), keyWord)){
if(keyMatch == num){
return bean;
}else{
keyMatch ++;
}
}
content = new StringBuilder();
}
}
return null;
}
}
package test.ne2;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.Security;
import java.security.cert.Certificate;
import java.util.UUID;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import com.itextpdf.text.Image;
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.PdfSignatureAppearance;
import com.itextpdf.text.pdf.PdfSignatureAppearance.RenderingMode;
import com.itextpdf.text.pdf.PdfStamper;
import com.itextpdf.text.pdf.security.BouncyCastleDigest;
import com.itextpdf.text.pdf.security.DigestAlgorithms;
import com.itextpdf.text.pdf.security.ExternalDigest;
import com.itextpdf.text.pdf.security.ExternalSignature;
import com.itextpdf.text.pdf.security.MakeSignature;
import com.itextpdf.text.pdf.security.MakeSignature.CryptoStandard;
import com.itextpdf.text.pdf.security.PrivateKeySignature;
public class SignPDFUtils {
/**
*@param password
* 秘钥密码
*@param keyStorePath
* 秘钥文件路径
*@param signPdfSrc
* 签名的PDF文件
*@param signImage
** 签名图片文件
** @param x
** x坐标
** @param y
** y坐标
** @return */
public static byte[] sign(String password, String keyStorePath, InputStream inputStream, String signImage, float x, float y, int page,String reason,String location) {
PdfReader reader = null;
ByteArrayOutputStream signPDFData = null;
PdfStamper stp = null;
FileInputStream fos = null;
try {
BouncyCastleProvider provider = new BouncyCastleProvider();
Security.addProvider(provider);
// KeyStore ks = KeyStore.getInstance("JKS", new BouncyCastleProvider());
KeyStore ks = KeyStore.getInstance("JKS");
fos = new FileInputStream(keyStorePath); // 私钥密码 为Pkcs生成证书是的私钥密码 123456
ks.load(fos, password.toCharArray());
String alias = (String) ks.aliases().nextElement();
// 获得私钥
PrivateKey privateKey = (PrivateKey) ks.getKey(alias, password.toCharArray());
// 获得证书链
Certificate[] chain = ks.getCertificateChain(alias);
reader = new PdfReader(inputStream);
signPDFData = new ByteArrayOutputStream();
//创建签章工具PdfStamper ,最后一个boolean参数
//false的话,pdf文件只允许被签名一次,多次签名,最后一次有效
//true的话,pdf可以被追加签名,验签工具可以识别出每次签名之后文档是否被修改
stp = PdfStamper.createSignature(reader, signPDFData, '\0', null, true);
stp.setFullCompression();
// 获取数字签章属性对象,设定数字签章的属性
PdfSignatureAppearance sap = stp.getSignatureAppearance();
// 设置签章原因
sap.setReason(reason);
// 设置签章地点
sap.setLocation(location);
// 使用png格式透明图片
Image image = Image.getInstance(signImage);
sap.setImageScale(0);
sap.setSignatureGraphic(image);
// 设置签章的显示方式,如下选择的是只显示图章(还有其他的模式,可以图章和签名描述一同显示)
sap.setRenderingMode(RenderingMode.GRAPHIC);
//设置签名的位置,页码,签名域名称,多次追加签名的时候,签名预名称不能一样
//签名的位置,是图章相对于pdf页面的位置坐标,原点为pdf页面左下角
//四个参数的分别是,图章左下角x,图章左下角y,图章右上角x,图章右上角y
sap.setVisibleSignature(new Rectangle(x, y, x + 185, y + 68), page,
UUID.randomUUID().toString().replaceAll("-", ""));
stp.getWriter().setCompressionLevel(5);
// 摘要算法
ExternalDigest digest = new BouncyCastleDigest();
// 签章算法
ExternalSignature signature = new PrivateKeySignature(privateKey, DigestAlgorithms.SHA512, provider.getName());
// ExternalSignature signature = new PrivateKeySignature(privateKey, DigestAlgorithms.SHA512, provider.getName());
// 进行盖章操作 CMS高级电子签名(CAdES)的长效签名规范
MakeSignature.signDetached(sap, digest, signature, chain, null, null, null, 0, CryptoStandard.CADES);
stp.close();
reader.close();
return signPDFData.toByteArray();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (signPDFData != null) {
try {
signPDFData.close();
} catch (IOException e) {
}
}
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
}
}
}
return null;
}
}
package test.ne2;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import test.ne2.bean.KeyWordBean;
import test.ne2.bean.SignPDFBean;
import test.ne2.bean.SignPDFRequestBean;
public class Test {
public static void main(String[] args) throws Exception {
/*
* 签章参数
*/
// String keyWord = "85000315"; // 签章关键字
// int page = 1; // 关键字所在页数
// int num = 1; // 取第n次出现的关键字
// String srcPDFPath = "D:\\pdf\\test2.pdf"; // 待签章pdf文件路径
// String outPDFPath = "D:\\pdf\\out.pdf"; // 签章后输出的pdf文件路径
// String sealPath = "D:\\pdf\\印章.png"; // 印章图片路径
// String keyStorePath = "D:\\pdf\\keystore"; // 证书文件路径
// String keyStorePass = "Jitadmin001"; // 证书密码
// String signReason = "设置签章原因"; // 设置签章原因,可以为空
// String signLocation = "设置签章地点 "; // 设置签章地点
List list = new ArrayList();
SignPDFBean bean1 = new SignPDFBean();
bean1.setKeyStorePass("11111111");
bean1.setKeyStorePath("D:\\pdf\\key\\keystore");
// bean1.setKeyStorePass("Jitadmin001");
// bean1.setKeyStorePath("D:\\pdf\\keystore");
bean1.setKeyWord("85000315");
bean1.setNum(1);
bean1.setPage(1);
bean1.setSealPath("D:\\pdf\\印章.png");
bean1.setSignLocation("知春路1");
bean1.setSignReason("孙测试1");
SignPDFBean bean2 = new SignPDFBean();
bean2.setKeyStorePass("Jitadmin001");
bean2.setKeyStorePath("D:\\pdf\\keystore");
bean2.setKeyWord("客户");
bean2.setNum(1);
bean2.setPage(1);
bean2.setSealPath("D:\\pdf\\印章2.png");
bean2.setSignLocation("知春路2");
bean2.setSignReason("孙测试2");
SignPDFBean bean3 = new SignPDFBean();
bean3.setKeyStorePass("Jitadmin001");
bean3.setKeyStorePath("D:\\pdf\\keystore");
bean3.setKeyWord("五");
bean3.setNum(1);
bean3.setPage(1);
bean3.setSealPath("D:\\pdf\\印章3.png");
bean3.setSignLocation("知春路3");
bean3.setSignReason("孙测试3");
list.add(bean1);
list.add(bean2);
list.add(bean3);
SignPDFRequestBean requestBean = new SignPDFRequestBean();
requestBean.setSrcPDFPath("D:\\pdf\\test2.pdf");
requestBean.setOutPDFPath("D:\\pdf\\out.pdf");
requestBean.setSignPDFBeans(list);
long startTime = System.currentTimeMillis();
// 1.解析pdf文件
Map> map = KeywordPDFUtils.getPDFText(requestBean.getSrcPDFPath());
// 2.获取关键字坐标
List beans = requestBean.getSignPDFBeans();
byte[] fileData = null;
InputStream in = null;
for (int i = 0; i
第一次写,排版很乱,大家见谅
参考文档:https://blog.csdn.net/javasun608/article/details/79307845
http://www.mamicode.com/info-detail-1942091.html
https://blog.csdn.net/modelsetget/article/details/80812550#comments