先看效果
支持pdf、Word、图片盖章。下面讲一下实现要点。
实现图片的拖拽,核心代码如下
其中id="sign"即为印章,id="image"即为pdf转换成的图片
function setSign(){
var container_top = $('#container').offset().top;
var container_left = $('#container').offset().left;
var container_width = $("#container").width();
var container_height = $("#container").height();
var sign_width = $("#sign").width();
var sign_height = $("#sign").height();
//锚定印章可移动的范围
var range = {
minX: container_left,
minY: container_top,
maxX: container_width + container_left - sign_width, //扣去2个padding=8px以及2个边框1px
maxY: container_height + container_top - sign_height
};
console.log(range);
//绑定移动事件
var sign = $('#sign');
//绑定移动事件
sign.on('mousedown', function (e) {
sign.data('x', e.clientX);
sign.data('y', e.clientY);
var position = sign.position();
$(document).on('mousemove', function (e1) {
var x = e1.clientX - sign.data('x') + position.left;
var y = e1.clientY - sign.data('y') + position.top;
x = x < range.minX ? range.minX : x;
x = x > range.maxX ? range.maxX : x;
y = y < range.minY ? range.minY : y;
y = y > range.maxY ? range.maxY : y;
sign.css({ left: x, top: y });
}).on('mouseup', function () {
$(this).off('mousemove').off('mouseup');
});
});
}
上述代码是为了实现印章的拖拽效果,同时限定印章的活动范围(不能超过PDF的范围)。
function gz() {
$("#gz_button").attr("disabled", true);
//获取container
var container_top = $('#container').offset().top;
var container_left = $('#container').offset().left;
var sign_top = $('#sign').offset().top;
var sign_left = $('#sign').offset().left;
var sign_width = $('#sign').outerWidth(true);
var sign_height = $('#sign').outerHeight(true);
var container_height = $('#container').height();
var container_width = $('#container').width();
var margin_left = parseInt(sign_left - container_left + sign_width / 2);
var margin_bottom = parseInt(container_height - sign_top + container_top - sign_height / 2);
console.log(margin_left, margin_bottom);
var left_percent = margin_left / container_width;
var bottom_percent = margin_bottom / container_height;
console.log(container_width, left_percent, bottom_percent);
//传递到后台
if (currentPage != 1) {
currentPage = $(".current_page").html();
}
console.log(currentPage);
$.ajax({
url:'/wechartminiprogram/ydqz/gz',
contentType: "application/json;charset=UTF-8",
dataType:'json',
type:'POST',
data: JSON.stringify({"fileName":fileName,"pageIndex":currentPage,"leftPercent":left_percent,"bottomPercent":bottom_percent,"signName":sign_name}),
responseType: 'blob',
success: function(data){
console.log(data);
if (data.code == 0) {
var form = $("
上述代码即为盖章按钮的点击事件,获取印章距PDF最左侧的百分比及最底部的百分比,传递给后台,同时因为PDF可能有多页,所以还需要将当前页的页码传递给后台。
依赖如下
org.apache.pdfbox
fontbox
2.0.17
org.apache.pdfbox
pdfbox
2.0.17
org.apache.pdfbox
pdfbox-tools
2.0.17
com.jacob
jacob
1.19
com.itextpdf
itextpdf
5.5.9
com.itextpdf.tool
xmlworker
5.5.9
com.itextpdf
itext-asian
5.2.0
pdf转图片:
private int pdf2png(String fileAddress,String filename,String type) {
// 将pdf装图片 并且自定义图片得格式大小
File file = new File(fileAddress+"\\"+filename+".pdf");
try {
PDDocument doc = PDDocument.load(file);
PDFRenderer renderer = new PDFRenderer(doc);
int pageCount = doc.getNumberOfPages();
for (int i = 0; i < pageCount; i++) {
BufferedImage image = renderer.renderImageWithDPI(i, 144); // Windows native DPI
// BufferedImage srcImage = resize(image, 240, 240);//产生缩略图
ImageIO.write(image, type, new File(fileAddress+"\\"+filename+"_"+(i+1)+"."+type));
}
doc.close();
return pageCount;
} catch (IOException e) {
e.printStackTrace();
}
return 0;
}
word转pdf:
private String word2pdf(String filePath) throws Exception{
ActiveXComponent app = null;
String pdfFileName = new Date().getTime() + "_converted";
String pdfFile = fileTempPath + File.separator + pdfFileName + ".pdf";
System.out.println("开始转换...");
// 开始时间
long start = System.currentTimeMillis();
try {
// 打开word
app = new ActiveXComponent("Word.Application");
// 设置word不可见,很多博客下面这里都写了这一句话,其实是没有必要的,因为默认就是不可见的,如果设置可见就是会打开一个word文档,对于转化为pdf明显是没有必要的
//app.setProperty("Visible", false);
// 获得word中所有打开的文档
Dispatch documents = app.getProperty("Documents").toDispatch();
System.out.println("打开文件: " + filePath);
// 打开文档
Dispatch document = Dispatch.call(documents, "Open", filePath, false, true).toDispatch();
// 如果文件存在的话,不会覆盖,会直接报错,所以我们需要判断文件是否存在
File target = new File(pdfFile);
if (target.exists()) {
target.delete();
}
System.out.println("另存为: " + pdfFile);
// 另存为,将文档报错为pdf,其中word保存为pdf的格式宏的值是17
Dispatch.call(document, "SaveAs", pdfFile, 17);
// 关闭文档
Dispatch.call(document, "Close", false);
// 结束时间
long end = System.currentTimeMillis();
System.out.println("转换成功,用时:" + (end - start) + "ms");
return pdfFileName;
}catch(Exception e) {
throw new RuntimeException("word转换成pdf失败" + e.getMessage());
}finally {
// 关闭office
app.invoke("Quit", 0);
}
}
图片转pdf:
private void image2pdf(String imagePath, String pdfPath) throws Exception{
Document document = new Document();
FileOutputStream fos = null;
try {
fos = new FileOutputStream(pdfPath);
PdfWriter.getInstance(document, fos);
// 设置文档的大小
document.setPageSize(PageSize.A4);
// 打开文档
document.open();
// 写入一段文字
// 读取一个图片
Image image = Image.getInstance(imagePath);
float imageHeight=image.getScaledHeight();
float imageWidth=image.getScaledWidth();
int i=0;
while(imageHeight>500||imageWidth>500){
image.scalePercent(100-i);
i ++;
imageHeight=image.getScaledHeight();
imageWidth=image.getScaledWidth();
}
image.setAlignment(Image.ALIGN_CENTER);
//设置图片的绝对位置
// image.setAbsolutePosition(0, 0);
// image.scaleAbsolute(500, 400);
// 插入一个图片
document.add(image);
} catch (DocumentException de) {
System.out.println(de.getMessage());
} catch (IOException ioe) {
System.out.println(ioe.getMessage());
}
document.close();
fos.flush();
fos.close();
}
由于我司合作的CA厂商提供的电子签章API只有通过关键字盖章的方法,所以我还需要在指定的盖章位置添加一段关键字:
private ByteArrayOutputStream addText(String filePath,String text, float leftPercent, float bottomPercent, int pageIndex){
ByteArrayOutputStream byteArrayOutputStream = null;
PdfReader pdfReader = null;
PdfStamper pdfStamper = null;
PdfContentByte pdfContentByte = null;
try {
BaseFont baseFont = BaseFont.createFont(NAME, ENCODE, BaseFont.NOT_EMBEDDED);
InputStream inputStream = new FileInputStream(new File(filePath)); // 读取pdf文件
pdfReader = new PdfReader(inputStream); // 加载文件到pdf引擎
Document document = new Document(pdfReader.getPageSize(pageIndex));
// 获取页面宽度
float widths = document.getPageSize().getWidth();
// 获取页面高度
float heights = document.getPageSize().getHeight();
int width = Math.round(widths * leftPercent);
int height = Math.round(heights * bottomPercent);
byteArrayOutputStream = new ByteArrayOutputStream();
pdfStamper = new PdfStamper(pdfReader, byteArrayOutputStream); // 加载模板
pdfContentByte = pdfStamper.getOverContent(pageIndex); // 获取顶部
pdfContentByte.beginText(); // 插入文字信息
pdfContentByte.setFontAndSize(baseFont, 1);
int len = Math.round(baseFont.getWidthPoint(text, 1) / 2);//文字长度
BaseColor baseColor = new BaseColor(0, 0, 0);//最后一个1为透明
pdfContentByte.setColorFill(baseColor);
pdfContentByte.setTextMatrix(width - len, height); // 设置文字在页面中的坐标
pdfContentByte.showText(text);
pdfContentByte.endText();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
pdfStamper.close();
pdfReader.close();
byteArrayOutputStream.close();
} catch (Exception _e) {
_e.printStackTrace();
}
}
return byteArrayOutputStream;
}
字体是透明的,不影响原PDF的内容。后面只要调用盖章的方法就可以了,不再赘述。