最近一直找发票合并的小工具,没想到这玩意儿还收费,想着就自己用pdfbox的库弄一个。最终效果如图:
1.maven依赖
<dependencies>
<dependency>
<groupId>org.apache.pdfbox</groupId>
<artifactId>pdfbox</artifactId>
<version>2.0.24</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.10</version>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.5.7</version>
</dependency>
</dependencies>
2.合并代码
网上绝大多数都是多个PDF文件合并成一个文件,每个PDF是单独的页面。想两张合成一张放到一个页面就只能自己改造了。
多文件合并成多页:
public static void mergeDocument(String path) throws Exception {
File file = new File(path);
if (file.isDirectory()){
PDFMergerUtility merger = new PDFMergerUtility();
File[] files = file.listFiles();
for (File tmp: files){
System.out.println(tmp.getAbsolutePath());
merger.addSource(tmp);
}
String out = path + File.separator + DateUtil.format(new Date(), DatePattern.PURE_DATETIME_PATTERN) + "合并发票.pdf";
merger.setDestinationFileName(out);
merger.mergeDocuments(MemoryUsageSetting.setupMainMemoryOnly());
}
}
多文件合成单页两张:
public class Reader {
/**
* 计算发票金额
* @param tmp
* @return
*/
@SneakyThrows
public static BigDecimal summary(File tmp) {
PDDocument doc = PDDocument.load(tmp);
//创建检索对象
PDFTextStripper pdfStripper = new PDFTextStripper();
String content = pdfStripper.getText(doc);
doc.close();
Pattern pattern = Pattern.compile("[¥¥]\\s*\\d+\\.\\d{2}");
Matcher matcher = pattern.matcher(content);
List<BigDecimal> amountList = new ArrayList<>();
String str = "";
while (matcher.find()){
str = matcher.group();
String amountStr = str.replaceAll("[¥¥]\\s*", "");
amountList.add(new BigDecimal(amountStr));
}
System.out.println(tmp.getName() +","+ str);
Collections.sort(amountList);
return amountList.get(amountList.size()-1);
}
}
public class Test {
/**
* 文件列表
* @param path
* @return
*/
public static List<String> fileList(String path){
List<String> result = new ArrayList<String>();
File file = new File(path);
if (file.isDirectory()){
File[] files = file.listFiles();
BigDecimal sum = BigDecimal.ZERO;
for (File tmp: files){
if (!tmp.getName().startsWith("test")){
result.add(tmp.getAbsolutePath());
BigDecimal ele = Reader.summary(tmp);
sum = sum.add(ele);
}
}
System.out.println("总金额:¥ "+sum.toPlainString());
}
return result;
}
public static void main(String[] args) throws Exception {
String path = "E:\\文档\\发票\\test\\test_"+ DateUtil.format(new Date(), "yyyyMMdd_HHmmss")+".pdf";
//创建空白文档
PDDocument document = new PDDocument();
//布局
LayerUtility layerUtility = new LayerUtility(document);
//添加文档
List<String> files = fileList("E:\\文档\\发票\\test");
//缩放比例
float scaleX = 0.95f;
float scaleY = 0.95f;
//创建空白页面
PDPage blankPage = new PDPage();
document.addPage(blankPage);
PDRectangle rectangle = blankPage.getMediaBox();
float height = rectangle.getHeight();
float width = rectangle.getWidth();
for (int i=0;i<files.size();i++){
String doc = files.get(i);
PDFormXObject formPdf = layerUtility.importPageAsForm(PDDocument.load(new FileInputStream(doc)), 0);
PDRectangle formSize = formPdf.getBBox();
float scaledWidth = formSize.getWidth() * scaleX;
float scaledHeight = formSize.getHeight() * scaleY;
while (height/2 < scaledHeight){
scaleY = scaleY - 0.05f;
scaledHeight = formSize.getHeight() * scaleY;
}
float tx = (width - scaledWidth) / 2;
float padding = (height - scaledHeight *2) / 4;
int v = i%2;
double ty = height - scaledHeight*(v+1) - padding*(2*v+1);
AffineTransform form = AffineTransform.getTranslateInstance(tx, ty);
form.scale(scaleX, scaleY);
layerUtility.appendFormAsLayer(blankPage, formPdf, form, String.valueOf(i));
if ((i+1)%2==0){
PDPageContentStream contentStream = new PDPageContentStream(document, blankPage, PDPageContentStream.AppendMode.APPEND, true, true);
//设置分割线
float[] a={5,5};
Color color = new Color(174, 174, 174);
contentStream.setStrokingColor(color);
contentStream.setLineDashPattern(a, 0);
contentStream.moveTo(0, 396); // 设置起点坐标
contentStream.lineTo(612, 396); // 设置终点坐标
contentStream.setLineWidth(1); // 设置线宽
contentStream.stroke(); // 绘制线条
contentStream.close();
//创建新页面
if (i<files.size()-1){
blankPage = new PDPage();
document.addPage(blankPage);
PDRectangle rectangleTmp = blankPage.getMediaBox();
height = rectangleTmp.getHeight();
width = rectangleTmp.getWidth();
}
}
//恢复缩放比
scaleY = 0.95f;
}
//设置文档属性
PDDocumentInformation pdd = document.getDocumentInformation();
pdd.setAuthor("du.k");
document.save(path);
document.close();
}
}
说明下,这个PDF的文档坐标是左下角是原点坐标,向右X轴增加,向上Y轴增加。大概如下图布局: