001package top.cenze.utils;
002
003import cn.hutool.core.io.FileUtil;
004import cn.hutool.core.util.ObjectUtil;
005import com.spire.xls.Workbook;
006import com.spire.xls.Worksheet;
007import com.spire.xls.core.spreadsheet.HTMLOptions;
008import lombok.SneakyThrows;
009import lombok.extern.slf4j.Slf4j;
010import org.springframework.web.multipart.MultipartFile;
011import top.cenze.utils.file.CZFileUtil;
012import top.cenze.utils.file.MultipartFileUtil;
013
014import java.io.File;
015
016/**
017 * @desc: excel转换工具
018 * https://huaweicloud.csdn.net/63875467dacf622b8df8ae8a.html
019 * https://repo.e-iceblue.cn/#browse/browse:maven-public:e-iceblue%2Fspire.xls.free%2F2.2.0%2Fspire.xls.free-2.2.0.jar
020 * https://blog.csdn.net/zhuocailing3390/article/details/122527100
021 * https://gitee.com/lookWord/itext7-demo/tree/master/src/main/java/com/tk/itext7demo/utils/excel
022 * https://blog.51cto.com/u_16175446/7287269
023 * @author: chengze
024 * @createByDate: 2024/1/5 9:19
025 */
026@Slf4j
027public class ExcelConvertUtil {
028    /**
029     * 转PDF(第一个sheet,全部填充至一页内,且列宽根据内容自动调整)
030     * @param excelFile         excel 文件
031     * @return
032     */
033    public static MultipartFile toPdf(MultipartFile excelFile) {
034        return toPdf(excelFile, 0, true, true);
035    }
036
037    /**
038     * 转PDF(第一个sheet,全部填充至一页内,且列宽根据内容自动调整)
039     * @param excelFile         excel 文件
040     * @param fitToPage         整个sheet是否都填充到一页PDF内(一页显示所有sheet内容)
041     * @return
042     */
043    public static MultipartFile toPdf(MultipartFile excelFile, Boolean fitToPage) {
044        return toPdf(excelFile, 0, fitToPage, true);
045    }
046
047    /**
048     * 转PDF
049     * @param excelFile         excel 文件
050     * @param sheetNum          第几个sheet(sheet索引,第一个从0开始)
051     * @param fitToPage         整个sheet是否都填充到一页PDF内(一页显示所有sheet内容)
052     * @param autoFitColumn     sheet列中的字符超过列宽,是否自动调整列宽
053     * @return
054     */
055    @SneakyThrows
056    public static MultipartFile toPdf(MultipartFile excelFile, Integer sheetNum, Boolean fitToPage, Boolean autoFitColumn) {
057        File inFile = CZFileUtil.loadFile(excelFile);
058        log.info("toPdf in file name: {}, length: {}, path: {}", inFile.getName(), inFile.length(), inFile.getPath());
059        if (ObjectUtil.isNull(inFile)) {
060            return null;
061        }
062
063        MultipartFile tmpFile = null;
064        File outFile = CZFileUtil.createPdfFile();
065        log.info("toPdf out file1 name: {}, length: {}, path: {}", outFile.getName(), outFile.length(), outFile.getPath());
066        toPdf(inFile.getPath(), outFile.getPath(), sheetNum, fitToPage, autoFitColumn);
067        outFile = CZFileUtil.loadFile(outFile.getPath());
068        log.info("toPdf out file2 name: {}, length: {}, path: {}", outFile.getName(), outFile.length(), outFile.getPath());
069        if (ObjectUtil.isNotNull(outFile) && FileUtil.exist(outFile)) {
070            tmpFile = MultipartFileUtil.getMultipartFile(outFile);
071        }
072
073        FileUtil.del(inFile);
074        FileUtil.del(outFile);
075
076        log.info("toPdf multi file name: {}, size: {}", tmpFile.getOriginalFilename(), tmpFile.getSize());
077
078        return tmpFile;
079    }
080
081    /**
082     * 转PDF
083     * @param inputFilePath     excel文件路径
084     * @param outputFilePath    输出pdf文件路径
085     * @param sheetNum          第几个sheet(sheet索引,第一个从0开始)
086     * @param fitToPage         整个sheet是否都填充到一页PDF内(一页显示所有sheet内容)
087     * @param autoFitColumn     sheet列中的字符超过列宽,是否自动调整列宽
088     */
089    public static void toPdf(String inputFilePath, String outputFilePath, Integer sheetNum, Boolean fitToPage, Boolean autoFitColumn) {
090        if (ObjectUtil.isNull(sheetNum)) {
091            sheetNum = 0;
092        }
093
094        Workbook wb = new Workbook();
095        // 引入Excel文件
096        wb.loadFromFile(inputFilePath);
097        Worksheet sheet = wb.getWorksheets().get(sheetNum);
098        // 所有内容都填充到一页中
099        if (ObjectUtil.isNotNull(fitToPage) && fitToPage) {
100            wb.getConverterSetting().setSheetFitToPage(true);
101        }
102        // 列宽自动调整
103        if (ObjectUtil.isNotNull(autoFitColumn) && autoFitColumn) {
104            for (int i = 1; i < sheet.getColumns().length; i++)
105            {
106                sheet.autoFitColumn(i);
107            }
108        }
109
110        sheet.saveToPdf(outputFilePath);
111    }
112
113    /**
114     * 转PNG(第一个sheet,全部填充至一页内,且列宽根据内容自动调整)
115     * @param excelFile
116     * @return
117     */
118    public static MultipartFile toPng(MultipartFile excelFile) {
119        return toPng(excelFile, 0, true, true);
120    }
121
122    /**
123     * 转PNG
124     * @param excelFile         excel 文件
125     * @param sheetNum          第几个sheet(sheet索引,第一个从0开始)
126     * @param fitToPage         整个sheet是否都填充到一页PNG内(一页显示所有sheet内容)
127     * @param autoFitColumn     sheet列中的字符超过列宽,是否自动调整列宽
128     * @return
129     */
130    @SneakyThrows
131    public static MultipartFile toPng(MultipartFile excelFile, Integer sheetNum, Boolean fitToPage, Boolean autoFitColumn) {
132        File inFile = CZFileUtil.loadFile(excelFile);
133        if (ObjectUtil.isNull(inFile)) {
134            return null;
135        }
136
137        MultipartFile tmpFile = null;
138        File outFile = CZFileUtil.createPngFile();
139        toPng(inFile.getPath(), outFile.getPath(), sheetNum, fitToPage, autoFitColumn);
140        outFile = CZFileUtil.loadFile(outFile.getPath());
141        if (ObjectUtil.isNotNull(outFile) && FileUtil.exist(outFile)) {
142            tmpFile = MultipartFileUtil.getMultipartFile(outFile);
143        }
144
145        FileUtil.del(inFile);
146        FileUtil.del(outFile);
147
148        return tmpFile;
149    }
150
151    /**
152     * 转PNG
153     * @param inputFilePath     excel文件路径
154     * @param outputFilePath    输出png文件路径
155     * @param sheetNum          第几个sheet(sheet索引,第一个从0开始)
156     * @param fitToPage         整个sheet是否都填充到一页Png内(一页显示所有sheet内容)
157     * @param autoFitColumn     sheet列中的字符超过列宽,是否自动调整列宽
158     */
159    public static void toPng(String inputFilePath, String outputFilePath, Integer sheetNum, Boolean fitToPage, Boolean autoFitColumn) {
160        if (ObjectUtil.isNull(sheetNum)) {
161            sheetNum = 0;
162        }
163
164        Workbook wb = new Workbook();
165        // 引入Excel文件
166        wb.loadFromFile(inputFilePath);
167        Worksheet sheet = wb.getWorksheets().get(sheetNum);
168        // 所有内容都填充到一页中
169        if (ObjectUtil.isNotNull(fitToPage) && fitToPage) {
170            wb.getConverterSetting().setSheetFitToPage(true);
171        }
172        // 列宽自动调整
173        if (ObjectUtil.isNotNull(autoFitColumn) && autoFitColumn) {
174            for (int i = 1; i < sheet.getColumns().length; i++)
175            {
176                sheet.autoFitColumn(i);
177            }
178        }
179
180        sheet.saveToImage(outputFilePath);
181    }
182
183    /**
184     * 转HTML(第一个sheet,全部填充至一页内,且列宽根据内容自动调整)
185     * @param excelFile
186     * @return
187     */
188    public static MultipartFile toHtml(MultipartFile excelFile) {
189        return toHtml(excelFile, 0, true, true);
190    }
191
192    /**
193     * 转HTML
194     * @param excelFile         excel 文件
195     * @param sheetNum          第几个sheet(sheet索引,第一个从0开始)
196     * @param fitToPage         整个sheet是否都填充到一页html内(一页显示所有sheet内容)
197     * @param autoFitColumn     sheet列中的字符超过列宽,是否自动调整列宽
198     * @return
199     */
200    @SneakyThrows
201    public static MultipartFile toHtml(MultipartFile excelFile, Integer sheetNum, Boolean fitToPage, Boolean autoFitColumn) {
202        File inFile = CZFileUtil.loadFile(excelFile);
203        if (ObjectUtil.isNull(inFile)) {
204            return null;
205        }
206
207        MultipartFile tmpFile = null;
208        File outFile = CZFileUtil.createHtmlFile();
209        toHtml(inFile.getPath(), outFile.getPath(), sheetNum, fitToPage, autoFitColumn);
210        outFile = CZFileUtil.loadFile(outFile.getPath());
211        if (ObjectUtil.isNotNull(outFile) && FileUtil.exist(outFile)) {
212            tmpFile = MultipartFileUtil.getMultipartFile(outFile);
213        }
214
215//        FileUtil.del(inFile);
216//        FileUtil.del(outFile);
217
218        return tmpFile;
219    }
220
221    /**
222     * 转HTML
223     * @param inputFilePath     excel文件路径
224     * @param outputFilePath    输出html文件路径
225     * @param sheetNum          第几个sheet(sheet索引,第一个从0开始)
226     * @param fitToPage         整个sheet是否都填充到一页html内(一页显示所有sheet内容)
227     * @param autoFitColumn     sheet列中的字符超过列宽,是否自动调整列宽
228     */
229    public static void toHtml(String inputFilePath, String outputFilePath, Integer sheetNum, Boolean fitToPage, Boolean autoFitColumn) {
230        if (ObjectUtil.isNull(sheetNum)) {
231            sheetNum = 0;
232        }
233
234        Workbook wb = new Workbook();
235        // 引入Excel文件
236        wb.loadFromFile(inputFilePath);
237        Worksheet sheet = wb.getWorksheets().get(sheetNum);
238        // 所有内容都填充到一页中
239        if (ObjectUtil.isNotNull(fitToPage) && fitToPage) {
240            wb.getConverterSetting().setSheetFitToPage(true);
241        }
242        // 列宽自动调整
243        if (ObjectUtil.isNotNull(autoFitColumn) && autoFitColumn) {
244            for (int i = 1; i < sheet.getColumns().length; i++)
245            {
246                sheet.autoFitColumn(i);
247            }
248        }
249
250        //Set embedded image as true
251        HTMLOptions options = new HTMLOptions();
252        options.setImageEmbedded(true);
253
254        sheet.saveToHtml(outputFilePath, options);
255    }
256
257    @SneakyThrows
258    public static void office2PDF(String inputFilePath, String outputFilePath) {
259//        // 测试word文档转pdf
260//// 创建输入流
261//        FileInputStream input = new FileInputStream(inputFilePath);
262//// 创建输出流
263//        FileOutputStream output = new FileOutputStream(outputFilePath);
264//
265//
266//        LocalOfficeManager.Builder builder = LocalOfficeManager.builder();
267//// 设置本地Office地址,推荐LibreOffice
268//        builder.officeHome("C:/Program Files/LibreOffice");
269//// 部署主机,本地启动
270//        builder.hostName("127.0.0.1");
271//// 部署端口,可以设置多个
272//        builder.portNumbers(9000, 9001, 9002);
273//// 单任务过期时间 默认:120000 2分钟
274//        builder.taskExecutionTimeout((long) (2 * 1000 * 60));
275//// 任务过期时间 默认:30000 3 秒
276//        builder.taskQueueTimeout((long) (1000 * 60 * 60));
277//// 可以执行的最大任务数,默认200
278//        builder.maxTasksPerProcess(100);
279//// 构建
280//        LocalOfficeManager manager = builder.build();
281//// 启动
282//        manager.start();
283//
284//        log.info("office2PDF start");
285//        LocalConverter converter = LocalConverter.builder().officeManager(manager).build();
286//        // 进行格式转换
287//        converter.convert(input).as(DefaultDocumentFormatRegistry.XLSX)
288//                .to(output).as(DefaultDocumentFormatRegistry.PDF).execute();
289//        log.info("office2PDF end");
290//
291//        // 关闭流
292//        output.close();
293//        input.close();
294//        manager.stop();
295//        DefaultExecutor exec = new DefaultExecutor();
296//        File tempFolder = new File(outputFilePath);
297//        // 同步等待
298//        Semaphore semaphore = new Semaphore(1);
299//        semaphore.acquire();
300//        ExecuteResultHandler erh = new ExecuteResultHandler() {
301//            @Override
302//            public void onProcessComplete(int i) {
303//                semaphore.release();
304//                //转换完成逻辑
305//            }
306//
307//            @Override
308//            public void onProcessFailed(ExecuteException e) {
309//                semaphore.release();
310//                //转换失败逻辑
311//                e.printStackTrace();
312//            }
313//        };
314//        String command = "soffice --invisible --convert-to pdf --outdir \"" + tempFolder.getAbsolutePath() + "\" \"" + officeFile.getAbsolutePath() + "\"";
315//        System.out.println("执行office文件转换任务,命令为" + command);
316//        exec.execute(CommandLine.parse(command), erh);
317//        // 等待执行完成
318//        semaphore.acquire();
319//        File file = new File(tempFolder.getAbsolutePath() + File.separator + officeFile.getName().substring(0, officeFile.getName().indexOf(".")) + ".pdf");
320//        if (!file.exists()) {
321//            // 转换失败逻辑
322//        }
323//        return file;
324    }
325}