事出原因
最近本职工作繁忙。可能偶尔晚上还需要打车回家,打车就涉及到个人优先支付车费的问题(为什么不开通企业账号,我也不知道,问BOSS去)。就会涉及到上传以及打印发票的问题。
滴滴发票,给的是两个PDF。分开打印浪费纸张。PDF合并转换的软件呢又需要会员。无奈。小帅丶就依靠自己三脚猫的能耐,用Java(iText)实现了一下PDF合并。还支持灰度、去除顶部广告操作哦~。
iText简介
在企业的信息系统中,报表处理一直占比较重要的作用,iText是一种生成PDF报表的Java组件。通过在服务器端使用Jsp或JavaBean生成PDF报表,客户端采用超链接显示或下载得到生成的报表,这样就很好解决了B/S系统的报表处理问题。
iText是著名的开放源码的站点SourceForge一个项目,是用于生成PDF文档的一个Java类库。通过iText不仅可以生成PDF或rtf的文档,而且可以将XML、Html文件转化为PDF文件。iText的安装非常方便,下载iText.jar文件后,只需要在系统的CLASSPATH中加入iText.jar的路径,在程序中就可以使用iText类库了。
信息来源:https://baike.baidu.com/item/Itext/4692931
大致思路
1.PDF转图片,并进行缩放处理,DPI设定为300
2.新建一个空白PDF(是提前创建好的哦~)
3.将第一步处理好的2个图片文件添加到空白PDF,设置透明度,缩放宽高比例符合A4大小,另存为PDF文件。
大功告成!
上代码
/**
* @Author 小帅丶
* @Description 滴滴打车发票和行程单合并版成一个PDF
* @Date 2022/5/12 19:05
* @param pdfParams - PDF数据
* @param isBanner - 是否保存行程单顶部滴滴企业宣传图
* @param isGray - 是否进行灰度处理图片
* @param grayType - 灰度类别
* @return java.io.ByteArrayOutputStream
**/
public static ByteArrayOutputStream mergeDiDiInvoiceAndTravelToOnePDF(List<PDFParams> pdfParams, boolean isBanner,
boolean isGray, Integer grayType) throws Exception {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
switch (grayType) {
case BufferedImage.TYPE_INT_RGB:
case BufferedImage.TYPE_INT_ARGB:
case BufferedImage.TYPE_INT_ARGB_PRE:
case BufferedImage.TYPE_INT_BGR:
case BufferedImage.TYPE_3BYTE_BGR:
case BufferedImage.TYPE_4BYTE_ABGR:
case BufferedImage.TYPE_4BYTE_ABGR_PRE:
case BufferedImage.TYPE_BYTE_GRAY:
case BufferedImage.TYPE_USHORT_GRAY:
case BufferedImage.TYPE_BYTE_BINARY:
case BufferedImage.TYPE_BYTE_INDEXED:
case BufferedImage.TYPE_USHORT_555_RGB:
break;
default:
throw new Exception("Unknown image type " +
grayType);
}
//先对PDF进行处理
BufferedImage invoiceBI;
BufferedImage travelBI;
Map<PDFType, BufferedImage> allImg = new HashMap<>();
long startTime = System.currentTimeMillis();
for (PDFParams pdfParam : pdfParams) {
boolean isDiDi = getPDFContent(pdfParam.getFilePath(),pdfParam.getPdfType());
if(isDiDi){
if (pdfParam.getPdfType().equals(PDFType.INVOICE)) {
invoiceBI = PDFToImageSample.pdfToBufferedImage(pdfParam.getFilePath(), DEFAULT_DPI).get(0);
if (isGray) {
invoiceBI = grayDealImage(invoiceBI, grayType);
}
allImg.put(PDFType.INVOICE, invoiceBI);
}
if (pdfParam.getPdfType().equals(PDFType.TRAVEL_ITINERARY)) {
travelBI = PDFToImageSample.pdfToBufferedImage(pdfParam.getFilePath(), DEFAULT_DPI).get(0);
if (isBanner) {
travelBI = travelBI.getSubimage(0, 0, travelBI.getWidth(), travelBI.getHeight() - TRAVEL_B);
} else {
travelBI = travelBI.getSubimage(0, TRAVEL_Y, travelBI.getWidth(), travelBI.getHeight() - TRAVEL_H);
}
if (isGray) {
travelBI = grayDealImage(travelBI, grayType);
}
allImg.put(PDFType.TRAVEL_ITINERARY, travelBI);
}
}else{
throw new Exception("非滴滴发票 或 行程单,请检查PDF内容");
}
}
System.out.println("PDF转图片耗时:" + (System.currentTimeMillis() - startTime));
//开始合并图片到PDF
if (!allImg.isEmpty()) {
//合成后的文件
PdfReader reader = new PdfReader(new FileInputStream(EMPTY_PDF));
PdfStamper stamper = new PdfStamper(reader, outputStream);
//将所有图片放在pdf文件的第1页
PdfContentByte over = stamper.getOverContent(1);
for (Map.Entry<PDFType, BufferedImage> billImg : allImg.entrySet()) {
BufferedImage bufferedImage = billImg.getValue();
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
ImageIO.write(bufferedImage, "jpg", outStream);
//图片
com.itextpdf.text.Image contractSealImg = com.itextpdf.text.Image.getInstance(outStream.toByteArray());
over.saveState();
PdfGState pdfGState = new PdfGState();
//给图片设置透明度
pdfGState.setFillOpacity(1F);
over.setGState(pdfGState);
Integer width = DEFAULT_IMG_WIDTH;
//缩放比例值
double scaleX = (double) width / bufferedImage.getWidth();
//计算等比缩放的高度
Integer height = (int) (scaleX * bufferedImage.getHeight());
//设置图片位置
if (billImg.getKey().equals(PDFType.INVOICE)) {
contractSealImg.setAbsolutePosition(ABSOLUTE_X, (width + height) / 2);
}
if (billImg.getKey().equals(PDFType.TRAVEL_ITINERARY)) {
if (isBanner) {
contractSealImg.setAbsolutePosition(ABSOLUTE_X, 0);
} else {
contractSealImg.setAbsolutePosition(ABSOLUTE_X, height / 2);
}
}
//设置图片大小
contractSealImg.scaleAbsolute(width, height);
//将图片添加到pdf文件
over.addImage(contractSealImg);
over.restoreState();
}
stamper.setFormFlattening(true);
stamper.close();
reader.close();
outputStream.close();
}
System.out.println("合成总耗时:" + (System.currentTimeMillis() - startTime));
return outputStream;
}
如何使用
小帅丶为了方便,将此功能实现发布在了微信小程序里面。搜索 小帅一点资讯 或者 点击下方卡片 即可直达体验哦!
功能实现暂无涉及到商用内容,所以此功能呢,目前也是免费使用哦~
也可以先看下视频操作。再进行体验哦~
温馨提示:目前只支持滴滴出行电子发票及行程报销单合并哦~
【PDF合并】滴滴出行电子发票及行程报销单【一页打印】