首页 > 编程语言 >java pdf数字签证(图片),根据关键字定位签证位置

java pdf数字签证(图片),根据关键字定位签证位置

时间:2023-11-20 11:36:57浏览次数:37  
标签:java String matchItem import 签证 pdf public

网上找了很多,最后还是结合了一下才能用。

 

用到的主要jar包:itextpdf-5.5.13.jar,bcprov-jdk15on-1.49.jar,bcpkix-jdk15on-1.50.jar

main测试:


import java.io.FileInputStream;
import java.io.FileOutputStream;

import static weaver.interfaces.workflow.action.hrm.Test.PdfUtils.PdfHelper.getKeyWordsByPath;

public class PdfTest {

public static void main(String[] args) throws Exception {
String KEYSTORE="签证";
char[] PASSWORD = "签证密码".toCharArray();//keystory密码
String SRC="C:\\Users\\65390\\Desktop\\HQTS-H23097034IN1-Certificate(Official).pdf" ;//原始pdf //H23111879IN
String DEST="C:\\Users\\65390\\Desktop\\HQTS-H23097034IN4-Certificate(Official).pdf" ;//第二个测试的pdf
String DEST2="C:\\Users\\65390\\Desktop\\H23076631IN.pdf" ;//签名完成的pdf
String chapterPath="C:\\Users\\65390\\Desktop\\szqz.png";//签章图片
String reason="数据不可更改";
String location="看你自己";

MatchItem matchItem = getKeyWordsByPath(DEST, "Signed:");

System.out.println("x:" + matchItem.getX() + "y:" + matchItem.getY() + "页数:" + matchItem.getPageNum());



PdfUtils.sign( new FileInputStream(DEST), new FileOutputStream(DEST2),
new FileInputStream(KEYSTORE), PASSWORD, reason, location, chapterPath,matchItem.getX(), matchItem.getY(),matchItem.getPageNum());
}

}

查找关键字:

import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.parser.PdfReaderContentParser;

import java.io.IOException;
import java.util.List;

public class PdfHelper {

/**
* @Description 用于供外部类调用获取关键字所在PDF文件坐标
* @param filepath
* @param keyWords
* @return float[]
*/
public static MatchItem getKeyWordsByPath(String filepath, String keyWords) {
MatchItem matchItem = null;
try{
PdfReader pdfReader = new PdfReader(filepath);
matchItem = getKeyWords(pdfReader, keyWords);
} catch (IOException e) {
e.printStackTrace();
}
return matchItem;
}

/**
* @Description 获取关键字所在PDF坐标
* @param pdfReader
* @param keyWords
* @return float[]
*/
private static MatchItem getKeyWords(PdfReader pdfReader, String keyWords) {
int page = 0;
try{
int pageNum = pdfReader.getNumberOfPages();
PdfReaderContentParser pdfReaderContentParser = new PdfReaderContentParser(pdfReader);
CustomRenderListener renderListener = new CustomRenderListener();
renderListener.setKeyWord(keyWords);
StringBuilder allText = null;
for (page = 1; page <= pageNum; page++) {
renderListener.setPage(page);
pdfReaderContentParser.processContent(page, renderListener);
List<MatchItem> matchItems = renderListener.getMatchItems();
if(matchItems != null && matchItems.size() > 0) {
//完全匹配
return matchItems.get(0);
}
List<MatchItem> allItems = renderListener.getAllItems();
allText = new StringBuilder();
for (MatchItem item : allItems) {
allText.append(item.getContent());
//关键字存在连续多个块中
if(allText.indexOf(keyWords) != -1) {
return item;
}
}


}
} catch (IOException e) {
e.printStackTrace();
}
return null;
}

}



import com.itextpdf.awt.geom.Rectangle2D;
import com.itextpdf.text.pdf.parser.ImageRenderInfo;
import com.itextpdf.text.pdf.parser.RenderListener;
import com.itextpdf.text.pdf.parser.TextRenderInfo;

import java.util.ArrayList;
import java.util.List;

public class CustomRenderListener implements RenderListener {

/**定位坐标的关键字*/
private String keyWord;
/**关键字所在的页数*/
private int page;
//所有匹配的项
private List<MatchItem> matchItems = new ArrayList<>();
//所有项
private List<MatchItem> allItems = new ArrayList<>();

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 List<MatchItem> getMatchItems() {
return matchItems;
}

public void setMatchItems(List<MatchItem> matchItems) {
this.matchItems = matchItems;
}

public List<MatchItem> getAllItems() {
return allItems;
}

public void setAllItems(List<MatchItem> allItems) {
this.allItems = allItems;
}

@Override
public void beginTextBlock() {

}

@Override
public void renderText(TextRenderInfo textRenderInfo) {
String text = textRenderInfo.getText();
Rectangle2D.Float boundingRectange = textRenderInfo.getBaseline().getBoundingRectange();
MatchItem matchItem = new MatchItem();
matchItem.setContent(text);
matchItem.setPageNum(page);
matchItem.setX(boundingRectange.x);
matchItem.setY(boundingRectange.y);
if (null != text && !" ".equals(text)) {
if(text.equalsIgnoreCase(keyWord)) {
matchItems.add(matchItem);
}
}
allItems.add(matchItem);
}

@Override
public void endTextBlock() {

}

@Override
public void renderImage(ImageRenderInfo imageRenderInfo) {

}
}

签证代码:

import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Image;
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.pdf.*;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.GeneralSecurityException;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.cert.Certificate;


import com.itextpdf.text.pdf.security.*;

public class PdfUtils {

public static void sign(InputStream src //需要签章的pdf文件路径
, OutputStream dest // 签完章的pdf文件路径
, InputStream p12Stream, //p12 路径
char[] password
, String reason //签名的原因,显示在pdf签名属性中,随便填
, String location, String chapterPath, float width, float height, int page) //签名的地点,显示在pdf签名属性中,随便填
throws GeneralSecurityException, IOException, DocumentException, java.io.IOException {
//读取keystore ,获得私钥和证书链
//KeyStore ks = KeyStore.getInstance("PKCS12");
KeyStore ks = KeyStore.getInstance("jks");
ks.load(p12Stream, password);
String alias = (String)ks.aliases().nextElement();
PrivateKey pk = (PrivateKey) ks.getKey(alias, password);
Certificate[] chain = ks.getCertificateChain(alias);

//下边的步骤都是固定的,照着写就行了,没啥要解释的
// Creating the reader and the stamper,开始pdfreader
PdfReader reader = new PdfReader(src);
//目标文件输出流
//创建签章工具PdfStamper ,最后一个boolean参数
//false的话,pdf文件只允许被签名一次,多次签名,最后一次有效
//true的话,pdf可以被追加签名,验签工具可以识别出每次签名之后文档是否被修改
PdfStamper stamper = PdfStamper.createSignature(reader, dest, '\0', null, false);
// 获取数字签章属性对象,设定数字签章的属性
PdfSignatureAppearance appearance = stamper.getSignatureAppearance();
appearance.setReason(reason);
appearance.setLocation(location);
//设置签名的位置,页码,签名域名称,多次追加签名的时候,签名预名称不能一样
int pageCount = reader.getNumberOfPages();
//签名的位置,是图章相对于pdf页面的位置坐标,原点为pdf页面左下角
//四个参数的分别是,图章左下角x,图章左下角y,图章右上角x,图章右上角y
appearance.setVisibleSignature(new Rectangle(width+650, height+13, 90, 90), page, "sig1");
//读取图章图片,这个image是itext包的image
Image image = Image.getInstance(chapterPath);
appearance.setSignatureGraphic(image);
appearance.setCertificationLevel(PdfSignatureAppearance.CERTIFIED_NO_CHANGES_ALLOWED);
//设置图章的显示方式,如下选择的是只显示图章(还有其他的模式,可以图章和签名描述一同显示)
appearance.setRenderingMode(PdfSignatureAppearance.RenderingMode.GRAPHIC);

// 这里的itext提供了2个用于签名的接口,可以自己实现,后边着重说这个实现
// 摘要算法
ExternalDigest digest = new BouncyCastleDigest();
// 签名算法
ExternalSignature signature = new PrivateKeySignature(pk, DigestAlgorithms.SHA1, null);
// 调用itext签名方法完成pdf签章CryptoStandard.CMS 签名方式,建议采用这种
MakeSignature.signDetached(appearance, digest, signature, chain, null, null, null, 0, MakeSignature.CryptoStandard.CMS);
}

标签:java,String,matchItem,import,签证,pdf,public
From: https://www.cnblogs.com/z-y-s/p/17843547.html

相关文章

  • [实验任务一]:JAVA和C++常见数据结构迭代器的使用
    信1305班共44名同学,每名同学都有姓名,学号和年龄等属性,分别使用JAVA内置迭代器和C++中标准模板库(STL)实现对同学信息的遍历,要求按照学号从小到大和从大到小两种次序输出学生信息。实验要求:1. 搜集并掌握JAVA和C++中常见的数据结构和迭代器的使用方法,例如,vector,list,map和set等......
  • Java开发者的Python快速进修指南:函数进阶
    在上一篇文章中,我们讲解了函数最基础常见的用法,今天我想在这里简单地谈一下函数的其他用法。尽管这些用法可能不是非常常见,但我认为它们仍然值得介绍。因此,我将单独为它们开设一个章节,并探讨匿名函数和装饰器函数这两种特殊的用法。匿名函数在Python中,匿名函数也被称为lambda函......
  • java曰期加减Calendar日历类型常见方法
    1.获取当前日期:Calendarcalendar=Calendar.getInstance();Datedate=calendar.getTime();2.日期加减://加一天calendar.add(Calendar.DAY_OF_MONTH,1);//减一天calendar.add(Calendar.DAY_OF_MONTH,-1);//加一小时calendar.add(Calendar.HOUR_OF_DAY,1);/......
  • java时间截和日期格式相互转换的方法java如何将两个日期之间比大小
    Java时间戳和日期格式相互转换的方法:1.将时间戳转换为日期格式:longtimestamp=System.currentTimeMillis();//获取当前时间戳SimpleDateFormatsdf=newSimpleDateFormat("yyyy-MM-ddHH:mm:ss");//定义日期格式Stringdate=sdf.format(newDate(timestamp));//......
  • Java基础知识回顾5-序列化和反序列化
    一、概念Java序列化是指把Java对象转换为字节序列的过程。Java反序列化是指把字节序列恢复为Java对象的过程。序列化作用:在传递和保存对象时,保存对象的完整性和可传递性,对象转换为字节流,可以站网络上传输或者保存在本地文件中。反序列化作用:根据字节流中保存的对象状态及描述信息......
  • Java之抽象类的详解
    1.1概述1.1.1抽象类引入父类中的方法,被它的子类们重写,子类各自的实现都不尽相同。那么父类的方法声明和方法主体,只有声明还有意义,而方法主体则没有存在的意义了(因为子类对象会调用自己重写的方法)。换句话说,父类可能知道子类应该有哪个功能,但是功能具体怎么实现父类是不清楚的(由......
  • java反序列化----CC7利用链学习笔记(Hashtable)
    目录java反序列化----CC7利用链学习笔记(Hashtable)环境搭建利用链java反序列化----CC7利用链学习笔记(Hashtable)环境搭建jdk8u71<dependency><groupId>commons-collections</groupId><artifactId>commons-collections</artifactId>......
  • JAVA注解(韩顺平)
    第一部分:三个基本的注解Override用于检查方法重写的语法是否正确Override的结构(ctrl+b可以查看该注解的结构)Deprecatedpackagecom.annotation;//测试@Deprecataed注解publicclassDeprecated{publicstaticvoidmain(String[]args){Dd=ne......
  • java.io.IOException: Problem reading font data.
    字体库问题:运行命令fc-list 在运行yuminstallfontconfig后并没有解决这个问题那就是是临时文件的问题在查看Tomcat下bin/catalina.sh文件找到java的JVM临时目录java.io.tmpdir的配置是CATALINA_TMPDIR=“$CATALINA_BASE”/tempCATALINA_BASE指向的是Tomcat安装目录,由于是迁......
  • Java实现压缩文件浅谈
    背景:在Java中,可以使用java.util.zip包提供的类来进行文件的压缩和解压缩操作。主要涉及的类有ZipOutputStream、ZipEntry、ZipInputStream和InflaterInputStream。压缩文件的步骤和原理:创建一个FileOutputStream对象,用于将压缩后的数据写入到文件中。创建一个BufferedOutp......