001package top.cenze.utils.file;
002
003import cn.hutool.core.collection.CollectionUtil;
004import cn.hutool.core.io.FileUtil;
005import cn.hutool.core.util.ObjectUtil;
006import cn.hutool.core.util.StrUtil;
007import lombok.SneakyThrows;
008import lombok.extern.slf4j.Slf4j;
009import org.apache.pdfbox.io.MemoryUsageSetting;
010import org.apache.pdfbox.multipdf.PDFMergerUtility;
011import org.apache.pdfbox.pdmodel.PDDocument;
012import org.apache.pdfbox.rendering.PDFRenderer;
013import org.springframework.web.multipart.MultipartFile;
014
015import javax.imageio.ImageIO;
016import java.awt.image.BufferedImage;
017import java.io.File;
018import java.io.FileInputStream;
019import java.io.IOException;
020import java.io.OutputStream;
021import java.net.HttpURLConnection;
022import java.net.URL;
023import java.util.List;
024
025/**
026 * PDF工具类
027 */
028@Slf4j
029public class PDFUtil {
030    /**
031     * 获取PDF总页数
032     * @throws IOException
033     */
034    public static int getPageNum(String src) throws IOException {
035        PDDocument pdDocument = null;
036        int pages = 0;
037
038        try {
039            pdDocument = getPDDocument(src);
040            pages = pdDocument.getNumberOfPages();
041        } catch (Exception e) {
042            e.printStackTrace();
043            log.error(e.getMessage(), e);
044        } finally {
045            if (pdDocument != null) {
046                pdDocument.close();
047            }
048        }
049
050        return pages;
051    }
052
053    /**
054     * PDF转图片 根据页码一页一页转
055     * @throws IOException
056     */
057    public static BufferedImage toImg(String src, int page) throws IOException {
058        PDDocument pdDocument = null;
059        /* dpi越大转换后越清晰,相对转换速度越慢 */
060        int dpi = 100;
061        page --;
062
063        try {
064            pdDocument = getPDDocument(src);
065            PDFRenderer renderer = new PDFRenderer(pdDocument);
066
067            int pages = pdDocument.getNumberOfPages();
068            log.info("PdfToImg pages: {}", pages);
069
070            if (page <= pages && page >= 0) {
071                BufferedImage image = renderer.renderImageWithDPI(page, dpi);
072
073                return image;
074            }
075        } catch (Exception e) {
076            e.printStackTrace();
077            log.error(e.getMessage(), e);
078        } finally {
079            if (pdDocument != null) {
080                pdDocument.close();
081            }
082        }
083
084        return null;
085    }
086
087    /**
088     * PDF转图片 根据页码一页一页转,写入输出流
089     * @throws IOException
090     * imgType:转换后的图片类型 jpg,png
091     */
092    public static void toImgOutputStream(OutputStream os, String src, int page, String imgType) throws IOException {
093
094        BufferedImage bufferedImage = toImg(src, page);
095
096        if (null != bufferedImage) {
097            ImageIO.write(bufferedImage, imgType, os);
098        }
099    }
100
101    private static PDDocument getPDDocument(String src) throws IOException {
102        if (StrUtil.isNotEmpty(src)) {
103            // http文件,需要使用文件下载链接,否则无法正常读取文件内容(比如使用在线浏览链接,读取则会失败)
104            if ("http".equalsIgnoreCase(src.substring(0, 4))) {
105                try{
106
107                    URL url= new URL(src);
108
109                    HttpURLConnection connection = (HttpURLConnection) url.openConnection();
110
111                    return PDDocument.load(connection.getInputStream());
112                }catch(Exception e) {
113                    log.error(e.getMessage(), e);
114                }
115            }
116            // 本地文件
117            else {
118                File file = new File(src);
119                FileInputStream inputStream = new FileInputStream(file);
120
121                return PDDocument.load(inputStream);
122            }
123        }
124
125        return null;
126    }
127
128    /**
129     * 多个文件合并为一个
130     * @param lstMultiFile
131     * @return
132     */
133    @SneakyThrows
134    public static MultipartFile mulFile2One(List<MultipartFile> lstMultiFile) {
135        if (CollectionUtil.isEmpty(lstMultiFile)) {
136            return null;
137        }
138
139        File pdf = CZFileUtil.createPdfFile();
140        if (ObjectUtil.isNull(pdf) || !FileUtil.exist(pdf)) {
141            return null;
142        }
143        log.info("mulFile2One to new file path: {}", pdf.getPath());
144
145        PDFMergerUtility mergePdf = new PDFMergerUtility();
146        for (MultipartFile file : lstMultiFile) {
147            if (ObjectUtil.isNull(file) || "".equals(file) || file.getSize() <= 0) {
148                continue;
149            }
150            log.info("mulFile2One file name: {}", file.getOriginalFilename());
151
152            mergePdf.addSource(file.getInputStream());
153        }
154
155        mergePdf.setDestinationFileName(pdf.getPath());     // 设置合并生成pdf文件路径
156        mergePdf.mergeDocuments(MemoryUsageSetting.setupMainMemoryOnly());  // 合并pdf
157
158        pdf = CZFileUtil.loadFile(pdf.getPath());
159        if (ObjectUtil.isNull(pdf) || !FileUtil.exist(pdf) || pdf.length() <= 0) {
160            return null;
161        }
162        log.info("mulFile2One return file name: {}, size: {}", pdf.getName(), pdf.length());
163
164        MultipartFile multipartFile = MultipartFileUtil.getMultipartFile(pdf);
165
166        FileUtil.del(pdf);
167
168        return multipartFile;
169    }
170}