檔案線上預覽(四)將word、txt、ppt、excel、圖片轉成pdf來實現線上預覽

2023-06-08 12:01:53

@


之前在寫檔案線上預覽時留下了一個小坑,當時比較推薦的做法是將各種型別的檔案都由後端統一轉成pdf格式再由前端進行展示,但是當時並沒有提供將各種型別的檔案轉pdf的方法,這次就來填一下這個坑。
前端線上預覽pdf檔案的實現方式可以參考這篇文章:《檔案線上預覽(三)使用js前端實現word、excel、pdf、ppt 線上預覽》中 PDF檔案實現前端預覽 部分。

事前準備

程式碼基於 aspose-words(用於word、txt轉pdf),itextpdf(用於ppt、圖片、excel轉pdf),所以事先需要在專案裡下面以下依賴

1、需要的maven依賴

		<dependency>    
  	  		<groupId>com.luhuiguo</groupId>    
   		 	<artifactId>aspose-words</artifactId>    
  		  	<version>23.1</version>
		</dependency>
		<!--  poi -->
		<dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi</artifactId>
            <version>5.2.0</version>
        </dependency>
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-ooxml</artifactId>
            <version>5.2.0</version>
        </dependency>
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-scratchpad</artifactId>
            <version>5.2.0</version>
        </dependency>
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-excelant</artifactId>
            <version>5.2.0</version>
        </dependency>
        <!-- itextpdf -->
        <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>itextpdf</artifactId>
            <version>5.5.13.2</version>
        </dependency>
        <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>itext-asian</artifactId>
            <version>5.2.0</version>
        </dependency>		        

2、後面用到的工具類程式碼:

package com.fhey.service.common.utils.file;

import cn.hutool.core.util.StrUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;

/**
 * @author fhey
 * @date 2023-04-20 11:15:58
 * @description: 檔案工具類
 */
public class FileUtil {
    private static final Logger logger = LoggerFactory.getLogger(FileUtil.class);

    //獲取新檔案的全路徑
    public static String getNewFileFullPath(String sourceFilePath, String destFilePath, String ext) {
        File destFile = new File(destFilePath);
        if (destFile.isFile()) {
            return destFilePath;
        }
        File sourceFile = new File(sourceFilePath);
        String sourceFileName = sourceFile.getName();
        if (sourceFile.isFile()) {
            return destFilePath + File.separator + sourceFileName.substring(0, sourceFileName.lastIndexOf(StrUtil.DOT)) + StrUtil.DOT + ext;
        }
        return destFilePath + File.separator + sourceFileName + StrUtil.DOT + ext;
    }

    //判斷檔案是否是圖片
    public static boolean isImage(File file) throws IOException {
        FileInputStream is = new FileInputStream(file);
        byte[] bytes = new byte[8];
        is.read(bytes);
        is.close();
        String type = bytesToHexString(bytes).toUpperCase();
        if (type.contains("FFD8FF") //JPEG(jpg)
                || type.contains("89504E47") //PNG
                || type.contains("47494638") //GIF
                || type.contains("49492A00") //TIFF(tif)
                || type.contains("424D") //Bitmap(bmp)
        ) {
            return true;
        }
        return false;
    }

    //將檔案頭轉換成16進位制字串
    public static String bytesToHexString(byte[] src) {
        StringBuilder builder = new StringBuilder();
        if (src == null || src.length <= 0) {
            return null;
        }
        for (int i = 0; i < src.length; i++) {
            int v = src[i] & 0xFF;
            String hv = Integer.toHexString(v);
            if (hv.length() < 2) {
                builder.append(0);
            }
            builder.append(hv);
        }
        return builder.toString();
    }

}

一、word檔案轉pdf檔案(支援doc、docx)

word轉pdf的方法比較簡單,aspose-words基本都被幫我們搞定了,doc、docx都能支援。

程式碼:

public static void wordToPdf(String wordPath, String pdfPath) throws Exception {
        pdfPath = FileUtil.getNewFileFullPath(wordPath, pdfPath, "pdf");
        File file = new File(pdfPath);
        FileOutputStream os = new FileOutputStream(file);
        Document doc = new Document(wordPath);
        doc.save(os, com.aspose.words.SaveFormat.PDF);
    }

驗證程式碼:

public static void main(String[] args) throws Exception {
        wordToPdf("D:\\書籍\\電子書\\其它\\《山海經》異獸圖.docx", "D:\\test");
    }

轉換效果如下,格式、圖文都沒什麼問題,doc、docx經過驗證也都能轉換成功

二、txt檔案轉pdf檔案

txt檔案轉pdf檔案程式碼直接複用word的即可

程式碼:

public static void txtToPdf(String txtPath, String pdfPath) throws Exception {
        wordToPdf(txtPath, pdfPath);
    }

驗證程式碼:

public static void main(String[] args) throws Exception {
        txtToPdf("D:\\書籍\\電子書\\國外名著\\君主論.txt", "D:\\test");
    }

轉換效果如下

三、PPT檔案轉pdf檔案(支援ppt、pptx)

PPT檔案轉pdf檔案,聽說你們公司不讓用ppt,那就讓我們把ppt轉成pdf再用吧。其實從這裡開始程式碼就開始複雜起來了,這裡用到了Apache poi、itextpdf、Graphics2D三個庫,於是我結合這三個庫同時相容ppt、pptx寫出了第一版程式碼

ppt轉pdf第一版程式碼

public static void pptToPdf(String pptPath, String pdfPath) throws IOException {
        pdfPath = FileUtil.getNewFileFullPath(pptPath, pdfPath, "pdf");
        com.itextpdf.text.Document document = null;
        FileOutputStream fileOutputStream = null;
        PdfWriter pdfWriter = null;
        try {
            InputStream inputStream = Files.newInputStream(Paths.get(pptPath));
            SlideShow<?, ?> slideShow;
            String ext = pptPath.substring(pptPath.lastIndexOf("."));
            if (ext.equals(".pptx")) {
                slideShow = new XMLSlideShow(inputStream);
            } else {
                slideShow = new HSLFSlideShow(inputStream);
            }
            Dimension dimension = slideShow.getPageSize();
            fileOutputStream = new FileOutputStream(pdfPath);
            //document = new com.itextpdf.text.Document(new com.itextpdf.text.Rectangle((float) dimension.getWidth(), (float) dimension.getHeight()));
            document = new com.itextpdf.text.Document();
            pdfWriter = PdfWriter.getInstance(document, fileOutputStream);
            document.open();
            for (Slide<?, ?> slide : slideShow.getSlides()) {
                // 設定字型, 解決中文亂碼
                setPPTFont(slide, "宋體");
                BufferedImage bufferedImage = new BufferedImage((int) dimension.getWidth(), (int) dimension.getHeight(), BufferedImage.TYPE_INT_RGB);
                Graphics2D graphics2d = bufferedImage.createGraphics();
                graphics2d.setPaint(Color.white);
                graphics2d.setFont(new java.awt.Font("宋體", java.awt.Font.PLAIN, 12));
                slide.draw(graphics2d);
                graphics2d.dispose();
                com.itextpdf.text.Image image = com.itextpdf.text.Image.getInstance(bufferedImage, null);
                image.scaleToFit((float) dimension.getWidth(), (float) dimension.getHeight());
                document.add(image);
                document.newPage();
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (document != null) {
                    document.close();
                }
                if (fileOutputStream != null) {
                    fileOutputStream.close();
                }
                if (pdfWriter != null) {
                    pdfWriter.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    private static void setPPTFont(Slide<?, ?> slide, String fontFamily) {
        // 設定字型, 解決中文亂碼
        for (Shape<?, ?> shape : slide.getShapes()) {
            if (shape instanceof TextShape) {
                TextShape textShape = (TextShape) shape;
                List<TextParagraph> textParagraphs = textShape.getTextParagraphs();
                for (TextParagraph textParagraph : textParagraphs) {
                    List<TextRun> textRuns = textParagraph.getTextRuns();
                    for (TextRun textRun : textRuns) {
                        textRun.setFontFamily(fontFamily);
                    }
                }
            }
        }
    }

驗證程式碼:

public static void main(String[] args) throws Exception {
        pptToPdf("C:\\Users\\jie\\Desktop\\預覽\\web\\files\\河西走廊見聞錄.pptx", "D:\\test");
    }

轉換效果如下

可以看到轉換效果並不怎麼好,ppt的內容展示不全。於是我開始在網上找解決方案,結果找到了一個很神奇的解決方案,就繪製的圖片先寫在一個PdfPTable物件上,再把PdfPTable物件放到document離去,於是我根據這個改了改程式碼寫出了第二版程式碼

ppt轉pdf第二版程式碼

public static void pptToPdf(String pptPath, String pdfPath) throws IOException {
        pdfPath = FileUtil.getNewFileFullPath(pptPath, pdfPath, "pdf");
        com.itextpdf.text.Document document = null;
        FileOutputStream fileOutputStream = null;
        PdfWriter pdfWriter = null;
        try {
            InputStream inputStream = Files.newInputStream(Paths.get(pptPath));
            SlideShow<?, ?> slideShow;
            String ext = pptPath.substring(pptPath.lastIndexOf("."));
            if (ext.equals(".pptx")) {
                slideShow = new XMLSlideShow(inputStream);
            } else {
                slideShow = new HSLFSlideShow(inputStream);
            }
            Dimension dimension = slideShow.getPageSize();
            fileOutputStream = new FileOutputStream(pdfPath);
            //document = new com.itextpdf.text.Document(new com.itextpdf.text.Rectangle((float) dimension.getWidth(), (float) dimension.getHeight()));
            document = new com.itextpdf.text.Document();
            pdfWriter = PdfWriter.getInstance(document, fileOutputStream);
            document.open();
            PdfPTable pdfPTable = new PdfPTable(1);
            for (Slide<?, ?> slide : slideShow.getSlides()) {
                // 設定字型, 解決中文亂碼
                setPPTFont(slide, "宋體");
                BufferedImage bufferedImage = new BufferedImage((int) dimension.getWidth(), (int) dimension.getHeight(), BufferedImage.TYPE_INT_RGB);
                Graphics2D graphics2d = bufferedImage.createGraphics();
                graphics2d.setPaint(Color.white);
                graphics2d.setFont(new java.awt.Font("宋體", java.awt.Font.PLAIN, 12));
                slide.draw(graphics2d);
                graphics2d.dispose();
                com.itextpdf.text.Image image = com.itextpdf.text.Image.getInstance(bufferedImage, null);
                image.scaleToFit((float) dimension.getWidth(), (float) dimension.getHeight());
                // 寫入單元格
                pdfPTable.addCell(new PdfPCell(image, true));
                document.add(pdfPTable);
                pdfPTable.deleteBodyRows();
                document.newPage();
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (document != null) {
                    document.close();
                }
                if (fileOutputStream != null) {
                    fileOutputStream.close();
                }
                if (pdfWriter != null) {
                    pdfWriter.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

轉換效果如下

可以看到ppt內容已經展示完整了,到此其實ppt轉pdf功能已經基本實現了,但是顯示效果依然不算完美畢竟我們其實想要的是在pdf裡和在ppt看的是一樣的效果,而且每頁ppt的長寬其實都是一樣的,所以我就在想能不能設定pdf每頁的長寬,把pdf每頁的長寬設定成和ppt的長寬一樣。於是我開始看初始化pdf document的原始碼設定

com.itextpdf.text.Document document = new com.itextpdf.text.Document();

然後發現com.itextpdf.text.Document除了預設的建構函式外還有這這樣一個建構函式:

public Document(Rectangle pageSize) {
        this(pageSize, 36.0F, 36.0F, 36.0F, 36.0F);
    }

然後com.itextpdf.text.Rectangle類點進去就發現了可以設定長寬的建構函式:

public Rectangle(float urx, float ury) {
        this(0.0F, 0.0F, urx, ury);
    }

於是我程式碼中的初始化Document進行如下調整(根據第一版程式碼改,第二版的PdfPTable可以不用了)

document = new com.itextpdf.text.Document();
//改成如下
document = new com.itextpdf.text.Document(new com.itextpdf.text.Rectangle((float) dimension.getWidth(), (float) dimension.getHeight()));

ppt轉pdf第三版程式碼(最終版)

public static void pptToPdf(String pptPath, String pdfPath) throws IOException {
        pdfPath = FileUtil.getNewFileFullPath(pptPath, pdfPath, "pdf");
        com.itextpdf.text.Document document = null;
        FileOutputStream fileOutputStream = null;
        PdfWriter pdfWriter = null;
        try {
            InputStream inputStream = Files.newInputStream(Paths.get(pptPath));
            SlideShow<?, ?> slideShow;
            String ext = pptPath.substring(pptPath.lastIndexOf("."));
            if (ext.equals(".pptx")) {
                slideShow = new XMLSlideShow(inputStream);
            } else {
                slideShow = new HSLFSlideShow(inputStream);
            }
            Dimension dimension = slideShow.getPageSize();
            fileOutputStream = new FileOutputStream(pdfPath);
            //document = new com.itextpdf.text.Document();
            document = new com.itextpdf.text.Document(new com.itextpdf.text.Rectangle((float) dimension.getWidth(), (float) dimension.getHeight()));
            pdfWriter = PdfWriter.getInstance(document, fileOutputStream);
            document.open();
            for (Slide<?, ?> slide : slideShow.getSlides()) {
                // 設定字型, 解決中文亂碼
                setPPTFont(slide, "宋體");
                BufferedImage bufferedImage = new BufferedImage((int) dimension.getWidth(), (int) dimension.getHeight(), BufferedImage.TYPE_INT_RGB);
                Graphics2D graphics2d = bufferedImage.createGraphics();
                graphics2d.setPaint(Color.white);
                graphics2d.setFont(new java.awt.Font("宋體", java.awt.Font.PLAIN, 12));
                slide.draw(graphics2d);
                graphics2d.dispose();
                com.itextpdf.text.Image image = com.itextpdf.text.Image.getInstance(bufferedImage, null);
                image.scaleToFit((float) dimension.getWidth(), (float) dimension.getHeight());
                document.add(image);
                document.newPage();
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (document != null) {
                    document.close();
                }
                if (fileOutputStream != null) {
                    fileOutputStream.close();
                }
                if (pdfWriter != null) {
                    pdfWriter.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

轉換效果如下

現在展示的效果已經和ppt上一樣了,而且經過驗證ppt和pptx都是可以轉換成功的。

四、圖片轉pdf檔案

圖片轉pdf用到了用到了Apache poi、itextpdf兩個庫,因為itextpdf支援解析的圖片有限,點開c讀取圖片的方法com.itextpdf.text.Image.getInstance,我們可以看到這樣一段原始碼:

 Image img;
            if (c1 == 71 && c2 == 73 && c3 == 70) {
                GifImage gif = new GifImage(url);
                img = gif.getImage(1);
                img = img;
                return img;
            }

            if (c1 == 255 && c2 == 216) {
                Jpeg var39 = new Jpeg(url);
                return var39;
            }

            Jpeg2000 var38;
            if (c1 == 0 && c2 == 0 && c3 == 0 && c4 == 12) {
                var38 = new Jpeg2000(url);
                return var38;
            }

            if (c1 == 255 && c2 == 79 && c3 == 255 && c4 == 81) {
                var38 = new Jpeg2000(url);
                return var38;
            }

            if (c1 == PngImage.PNGID[0] && c2 == PngImage.PNGID[1] && c3 == PngImage.PNGID[2] && c4 == PngImage.PNGID[3]) {
                var12 = PngImage.getImage(url);
                return var12;
            }

            if (c1 == 215 && c2 == 205) {
                ImgWMF var37 = new ImgWMF(url);
                return var37;
            }

            if (c1 != 66 || c2 != 77) {
                RandomAccessFileOrArray ra;
                String file;
                if (c1 == 77 && c2 == 77 && c3 == 0 && c4 == 42 || c1 == 73 && c2 == 73 && c3 == 42 && c4 == 0) {
                    ra = null;

                    try {
                        if (url.getProtocol().equals("file")) {
                            file = url.getFile();
                            file = Utilities.unEscapeURL(file);
                            ra = new RandomAccessFileOrArray(randomAccessSourceFactory.createBestSource(file));
                        } else {
                            ra = new RandomAccessFileOrArray(randomAccessSourceFactory.createSource(url));
                        }

                        img = TiffImage.getTiffImage(ra, 1);
                        img.url = url;
                        img = img;
                        return img;
                    } catch (RuntimeException var32) {
                        if (recoverFromImageError) {
                            img = TiffImage.getTiffImage(ra, recoverFromImageError, 1);
                            img.url = url;
                            Image var15 = img;
                            return var15;
                        }

                        throw var32;
                    } finally {
                        if (ra != null) {
                            ra.close();
                        }

                    }
                }

                if (c1 == 151 && c2 == 74 && c3 == 66 && c4 == 50 && c5 == 13 && c6 == 10 && c7 == 26 && c8 == 10) {
                    ra = null;

                    try {
                        if (url.getProtocol().equals("file")) {
                            file = url.getFile();
                            file = Utilities.unEscapeURL(file);
                            ra = new RandomAccessFileOrArray(randomAccessSourceFactory.createBestSource(file));
                        } else {
                            ra = new RandomAccessFileOrArray(randomAccessSourceFactory.createSource(url));
                        }

                        img = JBIG2Image.getJbig2Image(ra, 1);
                        img.url = url;
                        img = img;
                        return img;
                    } finally {
                        if (ra != null) {
                            ra.close();
                        }

                    }
                }

由此可以可知itextpdf支援解析的圖片只有gif、jpeg、png、bmp、wmf、tiff、 jbig2這幾種,這些其實已經基本包含了所有主流的圖片格式(百度圖片:所以我用的webp格式是非主流格式?),而且圖片格式不是光改字尾就行的,必須要用格式轉換器轉換。比如下面這張圖雖然字尾是jpeg,但通過檢檢視片資訊可知實際格式是webg格式itextpdf一樣無法解析

話不多說我們先結合Apache poi、itextpdf兩個庫簡單協定版基本的圖片轉換pdf程式碼

單圖片轉pdf第一版程式碼

public static void imageToPdf(String imgPath, String pdfPath) throws Exception {
        pdfPath = FileUtil.getNewFileFullPath(imgPath, pdfPath, "pdf");
        com.itextpdf.text.Document document = new com.itextpdf.text.Document();
        PdfWriter.getInstance(document, Files.newOutputStream(Paths.get(pdfPath)));
        document.open();
        com.itextpdf.text.Image image = com.itextpdf.text.Image.getInstance(imgPath);
        image.setAlignment(com.itextpdf.text.Image.ALIGN_CENTER);
        document.add(image);
        document.close();
    }

驗證程式碼:

public static void main(String[] args) throws Exception {
       imageToPdf("D:\\picture\\美女\\aa37a7be4196c07f43a3f776801d1b46.jpg", "D:\\test");
    }

轉換效果如下

從效果可以我們可以看到這個圖片其實是沒有顯示完全的, 其實小一點的圖片是沒什麼問題的,但是因為pdf設定的每頁都是A4大小,所以在圖片過大時會顯示不完整,所以我們在圖片過大時需要對圖片進行一些調整,調整後的程式碼如下:

單圖片轉pdf第二版程式碼

public static void imageToPdf(String imgPath, String pdfPath) throws Exception {
        pdfPath = FileUtil.getNewFileFullPath(imgPath, pdfPath, "pdf");
        com.itextpdf.text.Document document = new com.itextpdf.text.Document();
        PdfWriter.getInstance(document, Files.newOutputStream(Paths.get(pdfPath)));
        document.open();
        com.itextpdf.text.Image image = com.itextpdf.text.Image.getInstance(imgPath);
        float width = image.getWidth();
        float height = image.getHeight();
        float space = 50f;
        if (width > PageSize.A4.getWidth() - space || height > PageSize.A4.getHeight() - space) {
            image.scaleToFit(PageSize.A4.getWidth() - space, PageSize.A4.getHeight() - space);
        }
        image.setAlignment(com.itextpdf.text.Image.ALIGN_CENTER);
        document.add(image);
        document.close();
    }

轉換效果如下

可以看到現在圖片已經完整的顯示在pdf的頁面中了,到這裡你可能會有一個疑惑,為什麼這次不想上面ppt轉換pdf一樣把pdf的頁面長寬設定成和圖片一樣,而且去調整圖片的大小呢。之所以這樣做的原因是因為在接下來的多圖片轉換成一個pdf檔案時,往往是不能確保每張圖片的長寬比例是一樣的,為了確保每張圖片都能完整的顯示,所以只能調整圖片的大小。

將資料夾下的所有圖片導成一個pdf

將圖片一張一張的導成pdf畢竟很麻煩,比如我一個資料夾下面有很多張圖片,我想將該資料夾下的所有圖片都匯入pdf中做個《美人譜》,我該怎麼做呢?安排!於是程式碼調整成了下面這樣

支援多圖片轉pdf程式碼:

public static void imageToPdf(String imagePath, String pdfPath) throws Exception {
        pdfPath = FileUtil.getNewFileFullPath(imagePath, pdfPath, "pdf");
        File imageFile = new File(imagePath);
        File[] files;
        if (imageFile.isDirectory()) {
            files = imageFile.listFiles();
        } else {
            files = new File[]{imageFile};
        }
        imageToPdf(files, pdfPath);
    }

    public static void imageToPdf(File[] imageFiles, String pdfPath) throws Exception {
        com.itextpdf.text.Document document = new com.itextpdf.text.Document();
        PdfWriter.getInstance(document, Files.newOutputStream(Paths.get(pdfPath)));
        document.open();
        for (File file : imageFiles) {
            if (file.isFile() && FileUtil.isImage(file)) {
                try {
                    com.itextpdf.text.Image image = com.itextpdf.text.Image.getInstance(file.getAbsolutePath());
                    float width = image.getWidth();
                    float height = image.getHeight();
                    float space = 10f;
                    if (width > PageSize.A4.getWidth() - space || height > PageSize.A4.getHeight() - space) {
                        image.scaleToFit(PageSize.A4.getWidth() - space, PageSize.A4.getHeight() - space);
                    }
                    image.setAlignment(com.itextpdf.text.Image.ALIGN_CENTER);
                    //document.setMargins(50, 150, 50, 50);
                    //document.setPageSize(new com.itextpdf.text.Rectangle(width, height));
                    document.newPage();
                    document.add(image);
                } catch (Exception e) {
                    logger.error("圖片轉換失敗", e);
                }
            }
        }
        document.close();
    }

驗證程式碼:

public static void main(String[] args) throws Exception {
       imageToPdf("D:\\picture\\美女", "D:\\test\\美人譜.pdf");
    }

轉換效果如下

五、excel檔案轉pdf檔案

其實excel轉pdf在實際的應用場景中應該比較罕見,但是前面也說了這麼多檔案轉pdf的方式了,那excel轉pdf也就一併說說吧。

方式1 使用itextpdf

程式碼如下:

public static void excelToPdf(String excelPath, String pdfPath) throws DocumentException, IOException {
        pdfPath = FileUtil.getNewFileFullPath(excelPath, pdfPath, "pdf");
        try (Workbook workbook = WorkbookFactory.create(new File(excelPath))) {
            com.itextpdf.text.Document document = new com.itextpdf.text.Document();
            PdfWriter.getInstance(document, new FileOutputStream(pdfPath));
            document.open();
            BaseFont chineseFont = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
            Font font = new Font(chineseFont, 12, Font.NORMAL);
            DecimalFormat df = new DecimalFormat("#");
            for (Sheet sheet : workbook) {
                PdfPTable table = new PdfPTable(sheet.getRow(0).getPhysicalNumberOfCells());
                for (Row row : sheet) {
                    for (Cell cell : row) {
                        if (cell.getCellType() == CellType.NUMERIC) {
                            PdfPCell pdfPCell = new PdfPCell(new Paragraph(df.format(cell.getNumericCellValue()), font));
                            table.addCell(pdfPCell);
                        } else {
                            PdfPCell pdfPCell = new PdfPCell(new Paragraph(cell.toString(), font));
                            table.addCell(pdfPCell);
                        }
                    }
                }
                table.setHeaderRows(1);
                document.add(table);
            }
            document.close();
        }
    }

驗證程式碼:

public static void main(String[] args) throws Exception {
       excelToPdf("C:\\Users\\jie\\Desktop\\新建 Microsoft Excel 工作表.xlsx", "D:\\test");
    }

轉換效果如下

方式2 使用spire

因為spire不在maven中央倉庫裡以及阿里雲的maven倉庫中,所以在使用spire之前需要現在maven中設定新的maven倉庫地址,設定如下;

<repositories>
        <repository>
            <id>com.e-iceblue</id>
            <name>e-iceblue</name>
            <url>https://repo.e-iceblue.cn/repository/maven-public/</url>
        </repository>
    </repositories>

然後再pom中引入依賴:

收費:

<groupId>e-iceblue</groupId>
            <artifactId>spire.office</artifactId>
            <version>5.3.1</version>
        </dependency>

或者 免費的:

<groupId>e-iceblue</groupId>
            <artifactId>spire.office.free</artifactId>
            <version>5.3.1</version>
        </dependency>

免費版本基礎功能都能用

程式碼:

public static void excelToPdf2(String excelPath, String pdfPath) throws DocumentException, IOException, InvalidFormatException {
        pdfPath = FileUtil.getNewFileFullPath(excelPath, pdfPath, "pdf");
        com.spire.xls.Workbook wb = new com.spire.xls.Workbook();
        wb.loadFromFile(excelPath);
        wb.saveToFile(pdfPath, com.spire.xls.FileFormat.PDF);
    }

驗證程式碼:

public static void main(String[] args) throws Exception {
       excelToPdf2("C:\\Users\\jie\\Desktop\\新建 Microsoft Excel 工作表.xlsx", "D:\\test");
    }

轉換效果如下

工具類整體程式碼

好了到這裡就已經將word、txt、ppt、excel、圖片等檔案轉成pdf檔案實現方式已經全部說完了,感謝閱讀到這裡的朋友!最後附上文中用到的工具類的整體程式碼:

package com.fhey.service.common.utils.file;

import cn.hutool.core.util.StrUtil;
import com.aspose.words.Document;
import com.fhey.service.common.utils.FileUtil;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Font;
import com.itextpdf.text.PageSize;
import com.itextpdf.text.Paragraph;
import com.itextpdf.text.pdf.BaseFont;
import com.itextpdf.text.pdf.PdfPCell;
import com.itextpdf.text.pdf.PdfPTable;
import com.itextpdf.text.pdf.PdfWriter;
import org.apache.poi.hslf.usermodel.*;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.sl.usermodel.Shape;
import org.apache.poi.sl.usermodel.*;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xslf.usermodel.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.awt.Color;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.text.DecimalFormat;
import java.util.List;


public class FileConvertUtil {
    private static final Logger logger = LoggerFactory.getLogger(FileConvertUtil2.class);

    //將word轉成pdf
    public static void wordToPdf(String wordPath, String pdfPath) throws Exception {
        pdfPath = FileUtil.getNewFileFullPath(wordPath, pdfPath, "pdf");
        File file = new File(pdfPath);
        FileOutputStream os = new FileOutputStream(file);
        Document doc = new Document(wordPath);
        doc.save(os, com.aspose.words.SaveFormat.PDF);
    }

    //將txt轉成pdf
    public static void txtToPdf(String txtPath, String pdfPath) throws Exception {
        wordToPdf(txtPath, pdfPath);
    }

    //將圖片轉成pdf
    public static void imageToPdf(String imagePath, String pdfPath) throws Exception {
        pdfPath = FileUtil.getNewFileFullPath(imagePath, pdfPath, "pdf");
        File imageFile = new File(imagePath);
        File[] files;
        if (imageFile.isDirectory()) {
            files = imageFile.listFiles();
        } else {
            files = new File[]{imageFile};
        }
        imageToPdf(files, pdfPath);
    }

    //將圖片轉成pdf
    public static void imageToPdf(File[] imageFiles, String pdfPath) throws Exception {
        com.itextpdf.text.Document document = new com.itextpdf.text.Document();
        PdfWriter.getInstance(document, Files.newOutputStream(Paths.get(pdfPath)));
        document.open();
        for (File file : imageFiles) {
            if (file.isFile() && FileUtil.isImage(file)) {
                try {
                    com.itextpdf.text.Image image = com.itextpdf.text.Image.getInstance(file.getAbsolutePath());
                    float width = image.getWidth();
                    float height = image.getHeight();
                    float space = 10f;
                    if (width > PageSize.A4.getWidth() - space || height > PageSize.A4.getHeight() - space) {
                        image.scaleToFit(PageSize.A4.getWidth() - space, PageSize.A4.getHeight() - space);
                    }
                    image.setAlignment(com.itextpdf.text.Image.ALIGN_CENTER);
                    //document.setMargins(50, 150, 50, 50);
                    //document.setPageSize(new com.itextpdf.text.Rectangle(width, height));
                    document.newPage();
                    document.add(image);
                } catch (Exception e) {
                    logger.error("圖片轉換失敗", e);
                }
            }
        }
        document.close();
    }


    //將excel檔案轉成pdf
    public static void excelToPdf(String excelPath, String pdfPath) throws DocumentException, IOException {
        pdfPath = FileUtil.getNewFileFullPath(excelPath, pdfPath, "pdf");
        try (Workbook workbook = WorkbookFactory.create(new File(excelPath))) {
            com.itextpdf.text.Document document = new com.itextpdf.text.Document();
            PdfWriter.getInstance(document, new FileOutputStream(pdfPath));
            document.open();
            BaseFont chineseFont = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
            Font font = new Font(chineseFont, 12, Font.NORMAL);
            DecimalFormat df = new DecimalFormat("#");
            for (Sheet sheet : workbook) {
                PdfPTable table = new PdfPTable(sheet.getRow(0).getPhysicalNumberOfCells());
                for (Row row : sheet) {
                    for (Cell cell : row) {
                        if (cell.getCellType() == CellType.NUMERIC) {
                            PdfPCell pdfPCell = new PdfPCell(new Paragraph(df.format(cell.getNumericCellValue()), font));
                            table.addCell(pdfPCell);
                        } else {
                            PdfPCell pdfPCell = new PdfPCell(new Paragraph(cell.toString(), font));
                            table.addCell(pdfPCell);
                        }
                    }
                }
                table.setHeaderRows(1);
                document.add(table);
            }
            document.close();
        }
    }

    //將excel檔案轉成pdf
    public static void excelToPdf2(String excelPath, String pdfPath) throws DocumentException, IOException, InvalidFormatException {
        pdfPath = FileUtil.getNewFileFullPath(excelPath, pdfPath, "pdf");
        com.spire.xls.Workbook wb = new com.spire.xls.Workbook();
        wb.loadFromFile(excelPath);
        wb.saveToFile(pdfPath, com.spire.xls.FileFormat.PDF);
    }

    //將html轉成pdf
    public static void htmlToPdf(String htmlPath, String pdfPath) {
        try {
            pdfPath = FileUtil.getNewFileFullPath(pdfPath, pdfPath, "pdf");
            File file = new File(pdfPath); // 新建一個空白pdf檔案
            FileOutputStream os = new FileOutputStream(file);
            Document doc = new Document(htmlPath); // Address是將要被轉化的word檔案
            doc.save(os, com.aspose.words.SaveFormat.PDF);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //將ppt檔案轉成pdf
    public static void pptToPdf(String pptPath, String pdfPath) throws IOException {
        pdfPath = FileUtil.getNewFileFullPath(pptPath, pdfPath, "pdf");
        com.itextpdf.text.Document document = null;
        FileOutputStream fileOutputStream = null;
        PdfWriter pdfWriter = null;
        try {
            InputStream inputStream = Files.newInputStream(Paths.get(pptPath));
            SlideShow<?, ?> slideShow;
            String ext = pptPath.substring(pptPath.lastIndexOf("."));
            if (ext.equals(".pptx")) {
                slideShow = new XMLSlideShow(inputStream);
            } else {
                slideShow = new HSLFSlideShow(inputStream);
            }
            Dimension dimension = slideShow.getPageSize();
            fileOutputStream = new FileOutputStream(pdfPath);
            //document = new com.itextpdf.text.Document();
            document = new com.itextpdf.text.Document(new com.itextpdf.text.Rectangle((float) dimension.getWidth(), (float) dimension.getHeight()));
            pdfWriter = PdfWriter.getInstance(document, fileOutputStream);
            document.open();
            for (Slide<?, ?> slide : slideShow.getSlides()) {
                // 設定字型, 解決中文亂碼
                setPPTFont(slide, "宋體");
                BufferedImage bufferedImage = new BufferedImage((int) dimension.getWidth(), (int) dimension.getHeight(), BufferedImage.TYPE_INT_RGB);
                Graphics2D graphics2d = bufferedImage.createGraphics();
                graphics2d.setPaint(Color.white);
                graphics2d.setFont(new java.awt.Font("宋體", java.awt.Font.PLAIN, 12));
                slide.draw(graphics2d);
                graphics2d.dispose();
                com.itextpdf.text.Image image = com.itextpdf.text.Image.getInstance(bufferedImage, null);
                image.scaleToFit((float) dimension.getWidth(), (float) dimension.getHeight());
                document.add(image);
                document.newPage();
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (document != null) {
                    document.close();
                }
                if (fileOutputStream != null) {
                    fileOutputStream.close();
                }
                if (pdfWriter != null) {
                    pdfWriter.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    private static void setPPTFont(Slide<?, ?> slide, String fontFamily) {
        // 設定字型, 解決中文亂碼
        for (Shape<?, ?> shape : slide.getShapes()) {
            if (shape instanceof TextShape) {
                TextShape textShape = (TextShape) shape;
                List<TextParagraph> textParagraphs = textShape.getTextParagraphs();
                for (TextParagraph textParagraph : textParagraphs) {
                    List<TextRun> textRuns = textParagraph.getTextRuns();
                    for (TextRun textRun : textRuns) {
                        textRun.setFontFamily(fontFamily);
                    }
                }
            }
        }
    }
}