天天看點

文檔線上預覽(一)将txt、word、pdf轉成圖檔實作線上預覽功能

作者:知北遊zzz

如果不想網頁上的文章被複制(沒錯,說的就是某點),如果想實作文檔不需要下載下傳下來就能線上預覽檢視(常見于文檔付費下載下傳網站、郵箱附件預覽),該怎麼做?常見的做法就是将他們轉化成圖檔。以下代碼基于 aspose-words(用于txt、word轉圖檔),pdfbox(用于pdf轉圖檔),封裝成一個工具類來實作txt、word、pdf等檔案轉圖檔的需求。

首先在項目的pom檔案裡添加下面兩個依賴

<dependency>    
    <groupId>com.luhuiguo</groupId>    
    <artifactId>aspose-words</artifactId>    
    <version>23.1</version></dependency>
<dependency>    
    <groupId>org.apache.pdfbox</groupId>    
    <artifactId>pdfbox</artifactId>    
    <version>2.0.4</version>
</dependency>
           

一、将檔案轉換成圖檔,并生成到本地

1、将word檔案轉成圖檔

public static void wordToImage(String wordPath, String imagePath) throws Exception {
        Document doc = new Document(wordPath);
        File file = new File(wordPath);
        String filename = file.getName();
        String pathPre = imagePath + File.separator + filename.substring(0, filename.lastIndexOf("."));
        for (int i = 0; i < doc.getPageCount(); i++) {
            Document extractedPage = doc.extractPages(i, 1);
            String path = pathPre + (i + 1) + ".png";
            extractedPage.save(path, SaveFormat.PNG);
        }
    }
           

驗證:

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

驗證結果:

文檔線上預覽(一)将txt、word、pdf轉成圖檔實作線上預覽功能

2、将txt檔案轉成圖檔(同word檔案轉成圖檔)

public static void txtToImage(String txtPath, String imagePath) throws Exception {
        wordToImage(txtPath, imagePath);
    }
           

驗證:

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

驗證結果:

文檔線上預覽(一)将txt、word、pdf轉成圖檔實作線上預覽功能

3、将pdf檔案轉圖檔

public static void pdfToImage(String pdfPath, String imagePath) throws Exception {
        File file = new File(pdfPath);
        String filename = file.getName();
        String pathPre = imagePath + File.separator + filename.substring(0, filename.lastIndexOf("."));
        PDDocument doc = PDDocument.load(file);
        PDFRenderer renderer = new PDFRenderer(doc);
        for (int i = 0; i < doc.getNumberOfPages(); i++) {
            BufferedImage image = renderer.renderImageWithDPI(i, 144); // Windows native DPI
            String pathname = pathPre + (i + 1) + ".png";
            ImageIO.write(image, "PNG", new File(pathname));
        }
        doc.close();
    }
           

驗證:

public static void main(String[] args) throws Exception {
        FileConvertUtil.pdfToImage("D:\\書籍\\電子書\\其它\\自然哲學的數學原理.pdf", "D:\\test\\pdf");
    }
           

驗證結果:

文檔線上預覽(一)将txt、word、pdf轉成圖檔實作線上預覽功能

4、同時支援多種檔案類型轉成圖檔

public static void fileToImage(String sourceFilePath, String imagePath) throws Exception {
        String ext = sourceFilePath.substring(sourceFilePath.lastIndexOf("."));
        switch (ext) {
            case ".doc":
            case ".docx":
                wordToImage(sourceFilePath, imagePath);
                break;
            case ".pdf":
                pdfToImage(sourceFilePath, imagePath);
                break;
            case ".txt":
                txtToImage(sourceFilePath, imagePath);
                break;
            default:
                System.out.println("檔案格式不支援");
        }
    }
           

二、利用多線程提升檔案寫入本地的效率

在将牛頓大大的長達669頁的巨作《自然哲學的數學原理》時發現執行時間較長,執行花了140,281ms。但其實這種IO密集型的操作是通過使用多線程的方式來提升效率的,于是針對這點,我又寫了一版多線程的版本。

同步執行導出 自然哲學的數學原理.pdf 耗時:

文檔線上預覽(一)将txt、word、pdf轉成圖檔實作線上預覽功能

優化後的代碼如下:

public static void pdfToImageAsync(String pdfPath, String imagePath) throws Exception {
        long old = System.currentTimeMillis();
        File file = new File(pdfPath);
        PDDocument doc = PDDocument.load(file);
        PDFRenderer renderer = new PDFRenderer(doc);
        int pageCount = doc.getNumberOfPages();
        int numCores = Runtime.getRuntime().availableProcessors();
        ExecutorService executorService = Executors.newFixedThreadPool(numCores);
        for (int i = 0; i < pageCount; i++) {
            int finalI = i;
            executorService.submit(() -> {
                try {
                    BufferedImage image = renderer.renderImageWithDPI(finalI, 144); // Windows native DPI
                    String filename = file.getName();
                    filename = filename.substring(0, filename.lastIndexOf("."));
                    String pathname = imagePath + File.separator + filename + (finalI + 1) + ".png";
                    ImageIO.write(image, "PNG", new File(pathname));
                } catch (Exception ex) {
                    ex.printStackTrace();
                }
            });
        }
        executorService.shutdown();
        executorService.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
        doc.close();
        long now = System.currentTimeMillis();
        System.out.println("pdfToImage 多線程 轉換完成..用時:" + (now - old) + "ms");
    }
           

多線程執行導出 自然哲學的數學原理.pdf 耗時如下:

文檔線上預覽(一)将txt、word、pdf轉成圖檔實作線上預覽功能

從上圖可以看到本次執行隻花了24045ms,隻花了原先差不多六分之一的時間,極大地提升了執行效率。除了pdf,word、txt轉圖檔也可以做這樣的多線程改造:

//将word轉成圖檔(多線程)
    public static void wordToImageAsync(String wordPath, String imagePath) throws Exception {
        Document doc = new Document(wordPath);
        File file = new File(wordPath);
        String filename = file.getName();
        String pathPre = imagePath + File.separator + filename.substring(0, filename.lastIndexOf("."));
        int numCores = Runtime.getRuntime().availableProcessors();
        ExecutorService executorService = Executors.newFixedThreadPool(numCores);
        for (int i = 0; i < doc.getPageCount(); i++) {
            int finalI = i;
            executorService.submit(() -> {
                try {
                    Document extractedPage = doc.extractPages(finalI, 1);
                    String path = pathPre + (finalI + 1) + ".png";
                    extractedPage.save(path, SaveFormat.PNG);
                } catch (Exception ex) {
                    ex.printStackTrace();
                }
            });
        }
    }

    //将txt轉成圖檔(多線程)
    public static void txtToImageAsync(String txtPath, String imagePath) throws Exception {
        wordToImageAsync(txtPath, imagePath);
    }
           

三、将檔案轉換成圖檔流

​ 有的時候我們轉成圖檔後并不需要在本地生成圖檔,而是需要将圖檔傳回或者上傳到圖檔伺服器,這時候就需要将轉換後的圖檔轉成流傳回以友善進行傳輸,代碼示例如下:

1、将word檔案轉成圖檔流

public static List<byte[]> wordToImageStream(String wordPath) throws Exception {
    Document doc = new Document(wordPath);
    List<byte[]> list = new ArrayList<>();
    for (int i = 0; i < doc.getPageCount(); i++) {
        try(ByteArrayOutputStream outputStream = new ByteArrayOutputStream()){
            Document extractedPage = doc.extractPages(i, 1);
            extractedPage.save(outputStream, SaveFormat.*PNG*);
            list.add(outputStream.toByteArray());
        }
    }
    return list;
}
           

2、将txt檔案轉成圖檔流

public static List<byte[]> txtToImageStream(String txtPath) throws Exception {
    return *wordToImagetream*(txtPath);
}
           

3、将pdf轉成圖檔流

public static List<byte[]> pdfToImageStream(String pdfPath) throws Exception {
    File file = new File(pdfPath);
    PDDocument doc = PDDocument.*load*(file);
    PDFRenderer renderer = new PDFRenderer(doc);
    List<byte[]> list = new ArrayList<>();
    for (int i = 0; i < doc.getNumberOfPages(); i++) {
        try(ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
            BufferedImage image = renderer.renderImageWithDPI(i, 144); // Windows native DPI
            ImageIO.*write*(image, "PNG", outputStream);
            list.add(outputStream.toByteArray());
        }
    }
    doc.close();
    return list;
}
           

4、支援多種類型檔案轉成圖檔流

public static List<byte[]> fileToImageStream(String pdfPath) throws Exception {
    String ext = pdfPath.substring(pdfPath.lastIndexOf("."));
    switch (ext) {
        case ".doc":
        case ".docx":
            return *wordToImageStream*(pdfPath);
        case ".pdf":
            return *pdfToImageStream*(pdfPath);
        case ".txt":
            return *txtToImageStream*(pdfPath);
        default:
            System.*out*.println("檔案格式不支援");
    }
    return null;
}
           

最後附上完整的工具類代碼:

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

import com.aspose.words.Document;
import com.aspose.words.SaveFormat;
import com.aspose.words.SaveOptions;
import javassist.bytecode.ByteArray;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.rendering.PDFRenderer;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

public class FileConvertUtil {

    //檔案轉成圖檔
    public static void fileToImage(String sourceFilePath, String imagePath) throws Exception {
        String ext = sourceFilePath.substring(sourceFilePath.lastIndexOf("."));
        switch (ext) {
            case ".doc":
            case ".docx":
                wordToImage(sourceFilePath, imagePath);
                break;
            case ".pdf":
                pdfToImage(sourceFilePath, imagePath);
                break;
            case ".txt":
                txtToImage(sourceFilePath, imagePath);
                break;
            default:
                System.out.println("檔案格式不支援");
        }
    }

    //将pdf轉成圖檔
    public static void pdfToImage(String pdfPath, String imagePath) throws Exception {
        File file = new File(pdfPath);
        String filename = file.getName();
        String pathPre = imagePath + File.separator + filename.substring(0, filename.lastIndexOf("."));
        PDDocument doc = PDDocument.load(file);
        PDFRenderer renderer = new PDFRenderer(doc);
        for (int i = 0; i < doc.getNumberOfPages(); i++) {
            BufferedImage image = renderer.renderImageWithDPI(i, 144); // Windows native DPI
            String pathname = pathPre + (i + 1) + ".png";
            ImageIO.write(image, "PNG", new File(pathname));
        }
        doc.close();
    }

    //txt轉成轉成圖檔
    public static void txtToImage(String txtPath, String imagePath) throws Exception {
        wordToImage(txtPath, imagePath);
    }

    //将word轉成圖檔
    public static void wordToImage(String wordPath, String imagePath) throws Exception {
        Document doc = new Document(wordPath);
        File file = new File(wordPath);
        String filename = file.getName();
        String pathPre = imagePath + File.separator + filename.substring(0, filename.lastIndexOf("."));
        for (int i = 0; i < doc.getPageCount(); i++) {
            Document extractedPage = doc.extractPages(i, 1);
            String path = pathPre + (i + 1) + ".png";
            extractedPage.save(path, SaveFormat.PNG);
        }
    }

    //pdf轉成圖檔(多線程)
    public static void pdfToImageAsync(String pdfPath, String imagePath) throws Exception {
        long old = System.currentTimeMillis();
        File file = new File(pdfPath);
        PDDocument doc = PDDocument.load(file);
        PDFRenderer renderer = new PDFRenderer(doc);
        int pageCount = doc.getNumberOfPages();
        int numCores = Runtime.getRuntime().availableProcessors();
        ExecutorService executorService = Executors.newFixedThreadPool(numCores);
        for (int i = 0; i < pageCount; i++) {
            int finalI = i;
            executorService.submit(() -> {
                try {
                    BufferedImage image = renderer.renderImageWithDPI(finalI, 144); // Windows native DPI
                    String filename = file.getName();
                    filename = filename.substring(0, filename.lastIndexOf("."));
                    String pathname = imagePath + File.separator + filename + (finalI + 1) + ".png";
                    ImageIO.write(image, "PNG", new File(pathname));
                } catch (Exception ex) {
                    ex.printStackTrace();
                }
            });
        }
        executorService.shutdown();
        executorService.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
        doc.close();
        long now = System.currentTimeMillis();
        System.out.println("pdfToImage 多線程 轉換完成..用時:" + (now - old) + "ms");
    }

    //将word轉成圖檔(多線程)
    public static void wordToImageAsync(String wordPath, String imagePath) throws Exception {
        Document doc = new Document(wordPath);
        File file = new File(wordPath);
        String filename = file.getName();
        String pathPre = imagePath + File.separator + filename.substring(0, filename.lastIndexOf("."));
        int numCores = Runtime.getRuntime().availableProcessors();
        ExecutorService executorService = Executors.newFixedThreadPool(numCores);
        for (int i = 0; i < doc.getPageCount(); i++) {
            int finalI = i;
            executorService.submit(() -> {
                try {
                    Document extractedPage = doc.extractPages(finalI, 1);
                    String path = pathPre + (finalI + 1) + ".png";
                    extractedPage.save(path, SaveFormat.PNG);
                } catch (Exception ex) {
                    ex.printStackTrace();
                }
            });
        }
    }

    //将txt轉成圖檔(多線程)
    public static void txtToImageAsync(String txtPath, String imagePath) throws Exception {
        wordToImageAsync(txtPath, imagePath);
    }


    //将檔案轉成圖檔流
    public static List<byte[]> fileToImageStream(String pdfPath) throws Exception {
        String ext = pdfPath.substring(pdfPath.lastIndexOf("."));
        switch (ext) {
            case ".doc":
            case ".docx":
                return wordToImageStream(pdfPath);
            case ".pdf":
                return pdfToImageStream(pdfPath);
            case ".txt":
                return txtToImageStream(pdfPath);
            default:
                System.out.println("檔案格式不支援");
        }
        return null;
    }

    //将pdf轉成圖檔流
    public static List<byte[]> pdfToImageStream(String pdfPath) throws Exception {
        File file = new File(pdfPath);
        PDDocument doc = PDDocument.load(file);
        PDFRenderer renderer = new PDFRenderer(doc);
        List<byte[]> list = new ArrayList<>();
        for (int i = 0; i < doc.getNumberOfPages(); i++) {
            try(ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
                BufferedImage image = renderer.renderImageWithDPI(i, 144); // Windows native DPI
                ImageIO.write(image, "PNG", outputStream);
                list.add(outputStream.toByteArray());
            }
        }
        doc.close();
        return list;
    }

    //将word轉成圖檔流
    public static List<byte[]> wordToImageStream(String wordPath) throws Exception {
        Document doc = new Document(wordPath);
        List<byte[]> list = new ArrayList<>();
        for (int i = 0; i < doc.getPageCount(); i++) {
            try(ByteArrayOutputStream outputStream = new ByteArrayOutputStream()){
                Document extractedPage = doc.extractPages(i, 1);
                extractedPage.save(outputStream, SaveFormat.PNG);
                list.add(outputStream.toByteArray());
            }
        }
        return list;
    }

    //将txt轉成圖檔流
    public static List<byte[]> txtToImageStream(String txtPath) throws Exception {
        return wordToImageStream(txtPath);
    }
}