PDF发票合并

        最近一直找发票合并的小工具,没想到这玩意儿还收费,想着就自己用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轴增加。大概如下图布局:

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值