公司最近接到一个需求,需要电子签章,下面是简单的demo,参考了一些网上的文章,自己改一改
import com.itextpdf.awt.geom.Rectangle2D;
import com.itextpdf.text.Image;
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.pdf.*;
import com.itextpdf.text.pdf.parser.PdfReaderContentParser;
import com.yz.robot.api.spring.listener.TestRenderListener;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @Classname test
* @Author AlexZ
* @Date 2020/9/1 8:51
* @Version v1.0
* @Description
**/
public class test {
public static void main(String[] args) throws Exception {
// 模板文件路径
String templatePath = "XXXXXXpdfurl";
// 生成的文件 本地路径
String targetPath = "target.pdf";
//模拟用户传参
HashMap<String, String> hashMap = new HashMap<>(5);
hashMap.put("nameA", "xxxxxxxxxxxxxImageUrl");
hashMap.put("nameB", "xxxxxxxxxxxxxImageUrl");
hashMap.put("nameC", "xxxxxxxxxxxxxImageUrl");
URL url = new URL(templatePath);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
//设置超时间为3秒
conn.setConnectTimeout(3 * 1000);
//防止屏蔽程序抓取而返回403错误
conn.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)");
//得到输入流
InputStream input = conn.getInputStream();
// 读取模板文件
// InputStream input = new FileInputStream(new File(templatePath));
PdfReader reader = new PdfReader(input);
//新建一个PDF解析对象
PdfReaderContentParser parser = new PdfReaderContentParser(reader);
PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(targetPath));
for (int i = 1; i <= reader.getNumberOfPages(); i++) {
//新建一个ImageRenderListener对象,该对象实现了RenderListener接口,作为处理PDF的主要类
TestRenderListener listener = new TestRenderListener();
//解析PDF,并处理里面的文字
parser.processContent(i, listener);
//获取文字的矩形边框
List<Map<String, Rectangle2D.Float>> list_text = listener.rows_text_rect;
for (int k = 0; k < list_text.size(); k++) {
Map<String, Rectangle2D.Float> map = list_text.get(k);
for (Map.Entry<String, Rectangle2D.Float> entry : map.entrySet()) {
/**
* 此处name根据前端/移动端传参来指定规则
* 如前端传过来图片地址为nameA,我们匹配到的是$nameA,我们就截取$
* 这样就可以相互匹配上了
*/
String name = entry.getKey().replace("$", "");
Rectangle2D rectangle2D = entry.getValue();
float x = ((Rectangle2D.Float) rectangle2D).x;
float y = ((Rectangle2D.Float) rectangle2D).y;
float width = ((Rectangle2D.Float) rectangle2D).width;
float height = ((Rectangle2D.Float) rectangle2D).height;
// 读图片
Image image = Image.getInstance(hashMap.get(name));
//url远程文件旋转需要使用setRotationDegrees 本地使用setRotation
image.setRotationDegrees(90f);
// 获取操作的页面
PdfContentByte under = stamper.getOverContent(i);
// 根据域的大小缩放图片
image.scaleToFit(width, height);
// 添加图片
image.setAbsolutePosition(x, y);
under.addImage(image);
}
}
}
stamper.close();
reader.close();
System.exit(0);
}
}
import java.awt.Color;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import javax.imageio.ImageIO;
import com.itextpdf.awt.geom.Rectangle2D;
import com.itextpdf.awt.geom.RectangularShape;
import com.itextpdf.text.BaseColor;
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.pdf.PdfContentByte;
import com.itextpdf.text.pdf.parser.ImageRenderInfo;
import com.itextpdf.text.pdf.parser.RenderListener;
import com.itextpdf.text.pdf.parser.TextRenderInfo;
import org.apache.log4j.Logger;
public class TestRenderListener implements RenderListener {
private static final Logger logger = Logger.getLogger(TestRenderListener.class);
//用来存放每一行文字的坐标位置
public List<Map<String, Rectangle2D.Float>> rows_text_rect = new ArrayList<>();
//PDF文件的路径
protected String filepath = null;
public TestRenderListener() {
}
//step 2,遇到"BT"执行
@Override
public void beginTextBlock() {
// TODO Auto-generated method stub
}
//step 3
/**
* 文字主要处理方法
*/
@Override
public void renderText(TextRenderInfo renderInfo) {
//获取文字的下面的矩形
//Rectangle2D.Float rectBase = renderInfo.getBaseline().getBoundingRectange();
String text = renderInfo.getText();
if (text.indexOf("$name") != -1) {
RectangularShape rectBase = renderInfo.getBaseline().getBoundingRectange();
//获取文字下面的矩形
Rectangle2D.Float rectAscen = renderInfo.getAscentLine().getBoundingRectange();
//计算出文字的边框矩形
float leftX = (float) rectBase.getMinX();
float leftY = (float) rectBase.getMinY() - 10;
float rightX = (float) rectAscen.getMaxX();
float rightY = (float) rectAscen.getMaxY() + 10;
Rectangle2D.Float rect = new Rectangle2D.Float(leftX, leftY + 5, rightX - leftX + 10, rightY - leftY + 20);
logger.info("text:" + text + "--x:" + rect.x + "--y:" + rect.y + "--width:" + rect.width + "--height:" + rect.height);
Map<String, Rectangle2D.Float> map = new HashMap<>();
map.put(text, rect);
rows_text_rect.add(map);
}
}
//step 4(最后执行的,只执行一次),遇到“ET”执行
@Override
public void endTextBlock() {
// TODO Auto-generated method stub
}
//step 1(图片处理方法)
@Override
public void renderImage(ImageRenderInfo renderInfo) {
}
}
实现前后效果图: