Word 文档转换 PDF、图片

工作有需要 Word 文档转换 PDF、图片 的场景,我们来看看 Java 开发中怎么解决这个问题的。

Word 转 PDF

Word 转 PDF 分为商用 Aspose 方案和开源 Apache POI+iText 方案。

Aspose 方案

这种方式在目前来看应该是最好的,无论是转换的速度还是成功的概率,还支持的文件类型。

由于 Aspose 并非开源软件,不会在 Maven 公开依赖,故我们要手动加入到 Maven 管理中去。

xml 复制代码
<!-- Word2PDF -->
<dependency>
    <groupId>com.aspose</groupId>
    <artifactId>aspose-words</artifactId>
    <version>15.8</version>
    <scope>system</scope>
    <systemPath>${project.basedir}/jar/aspose-words-15.8.0-jdk16.jar</systemPath>
</dependency>

添加依赖

因为是手动添加的包,MANIFEST.MF 也要加入,不然启动程序的时候不知道要加入这个 jar 包。增加一个manifestEntries节点:

xml 复制代码
<manifestEntries>
    <!--MANIFEST.MF 中 Class-Path 加入资源文件目录 -->
    <Class-Path>lib/aspose-words-15.8.0-jdk16.jar</Class-Path>
</manifestEntries>

新增于 pom.xml 的<plugins>位置如图:

拷贝 jar 包,除了 runtime 的还有刚新家的 system 包,新增一个copy-dependencies2

xml 复制代码
<execution>
     <id>copy-dependencies2</id>
     <phase>package</phase>
     <goals>
         <goal>copy-dependencies</goal>
     </goals>
     <configuration>
         <outputDirectory>${project.build.directory}/lib</outputDirectory>
         <includeScope>system</includeScope>
     </configuration>
 </execution>

新增于 pom.xml 的<plugins>位置如图:

转换程序

java 复制代码
import com.aspose.words.Document;
import com.aspose.words.ImageSaveOptions;
import com.aspose.words.License;
import com.aspose.words.SaveFormat;

import java.io.ByteArrayInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;

/**
 * <a href="https://www.cnblogs.com/excellencesy/p/11603892.html">...</a>
 * <a href="https://blog.csdn.net/weixin_44605704/article/details/102572130">...</a>
 */
public class AsposeUtil {
    /**
     * Word 转 PDF
     *
     * @param wordPath Word 路径
     * @param pdfPath  PDF 路径
     */
    public static void word2pdf(String wordPath, String pdfPath) {
        AsposeUtil.getLicense();

        try (FileOutputStream os = new FileOutputStream(pdfPath)) {
            long old = System.currentTimeMillis();

            //设置一个字体目录(必须设置,否则生成的pdf乱码)下面这行代码不加的话在windows系统下生成的pdf不存在乱码问题,但是在linux系统下会乱码,linux下乱码解决方案请看后面的解决方案
            //FontSettings.setFontsFolder("/usr/share/fonts/chinese", false);
            new Document(wordPath).save(os, SaveFormat.PDF);

            System.out.println("word2pdf共耗时:" + (System.currentTimeMillis() - old) / 1000.0 + "秒");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void word2img(String wordPath, String outputDir) {
        AsposeUtil.getLicense();

        try {
            long old = System.currentTimeMillis();
            Document doc = new Document(wordPath);

            // 创建图像保存选项对象
            ImageSaveOptions options = new ImageSaveOptions(SaveFormat.JPEG);
            options.setPageCount(doc.getPageCount()); // 设置要转换的页数
//            options.setResolution(300); // 设置图像分辨率,默认为96dpi

            // 逐页转换并保存为图像
            for (int pageIndex = 0; pageIndex < doc.getPageCount(); pageIndex++) {
                String outputFileName = outputDir + "image_" + (pageIndex + 1) + ".png";
                options.setPageIndex(pageIndex);
                doc.save(outputFileName, options);
            }

            System.out.println("word2pdf共耗时:" + (System.currentTimeMillis() - old) / 1000.0 + "秒");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private static final byte[] LICENSE = ("<License>\n" +
            "    <Data>\n" +
            "        <Products>\n" +
            "            <Product>Aspose.Total for Java</Product>\n" +
            "            <Product>Aspose.Words for Java</Product>\n" +
            "        </Products>\n" +
            "        <EditionType>Enterprise</EditionType>\n" +
            "        <SubscriptionExpiry>20991231</SubscriptionExpiry>\n" +
            "        <LicenseExpiry>20991231</LicenseExpiry>\n" +
            "        <SerialNumber>8bfe198c-7f0c-4ef8-8ff0-acc3237bf0d7</SerialNumber>\n" +
            "    </Data>\n" +
            "    <Signature>sNLLKGMUdF0r8O1kKilWAGdgfs2BvJb/2Xp8p5iuDVfZXmhppo+d0Ran1P9TKdjV4ABwAgKXxJ3jcQTqE/2IRfqwnPf8itN8aFZlV3TJPYeD3yWE7IT55Gz6EijUpC7aKeoohTb4w2fpox58wWoF3SNp6sK6jDfiAUGEHYJ9pjU=</Signature>\n" +
            "</License>").getBytes();

    /**
     * 判断是否有授权文件 如果没有则会认为是试用版,转换的文件会有水印
     */
    public static void getLicense() {
        try (InputStream is = new ByteArrayInputStream(LICENSE)) {
            new License().setLicense(is);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

}

Apache ------iText 方案

xml 复制代码
<!-- POI Word2Pdf -->
<dependency>
    <groupId>fr.opensagres.xdocreport</groupId>
    <artifactId>org.apache.poi.xwpf.converter.pdf</artifactId>
    <version>1.0.6</version>
</dependency>

转换程序

java 复制代码
import fr.opensagres.xdocreport.utils.StringUtils;
import org.apache.poi.xwpf.converter.pdf.PdfConverter;
import org.apache.poi.xwpf.converter.pdf.PdfOptions;
import org.apache.poi.xwpf.usermodel.*;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;
import java.util.Map;

/**
 * @author Rocca
 */
public class WordPdfUtils {

    /**
     * 将word文档, 转换成pdf, 中间替换掉变量
     *
     * @param source 源为word文档, 必须为docx文档
     * @param target 目标输出
     * @param params 需要替换的变量
     */
    public static void wordConverterToPdf(InputStream source, OutputStream target, Map<String, String> params) {
        wordConverterToPdf(source, target, null, params);
    }

    /**
     * 将word文档, 转换成pdf, 中间替换掉变量
     *
     * @param source  源为word文档, 必须为docx文档
     * @param target  目标输出
     * @param params  需要替换的变量
     * @param options PdfOptions.create().fontEncoding( "windows-1250" ) 或者其他
     */
    public static void wordConverterToPdf(InputStream source, OutputStream target, PdfOptions options, Map<String, String> params) {
        long old = System.currentTimeMillis();

        try {
            XWPFDocument doc = new XWPFDocument(source);
            paragraphReplace(doc.getParagraphs(), params);

            for (XWPFTable table : doc.getTables()) {
                for (XWPFTableRow row : table.getRows()) {
                    for (XWPFTableCell cell : row.getTableCells())
                        paragraphReplace(cell.getParagraphs(), params);
                }
            }

            PdfConverter.getInstance().convert(doc, target, options);
            System.out.println("word2pdf共耗时:" + (System.currentTimeMillis() - old) / 1000.0 + "秒");
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 替换段落中内容
     */
    private static void paragraphReplace(List<XWPFParagraph> paragraphs, Map<String, String> params) {
        for (XWPFParagraph p : paragraphs) {
            for (XWPFRun r : p.getRuns()) {
                String content = r.getText(r.getTextPosition());
                if (StringUtils.isNotEmpty(content) && params.containsKey(content)) r.setText(params.get(content), 0);
            }
        }
    }

}

PDF 转图片

上述的 Aspose.Word 并不支持 PDF 转图片。要使用 Aspose PDF 转图片须使用他家的另外一个产品 Aspose.Pdf。另外有趣的是,Aspose.Word 可以直接转为图片,但由于当前需求是得到了 Pdf 加盖章和签名之后转换图片的,并不能从 Word 直接转图片。而且感觉 Word 转图片也比较慢。

我感觉 PDF 转图片比较简单,不用 Aspose 也行,------于是使用了 Apache 的 Pdfbox。

xml 复制代码
<!-- PDF2Img -->
<dependency>
    <groupId>org.apache.pdfbox</groupId>
    <artifactId>pdfbox</artifactId>
    <version>3.0.0</version>
</dependency>

你可以调整 DPI 分辨率,跟图片格式,下面例子是 gif 的。

java 复制代码
/**
 * PDF 转图片
 *
 * @param pdfFile PDF 文件
 */
public static void pdf2Img(String pdfFile, String outputDir) {
    long old = System.currentTimeMillis();

    try (PDDocument document = Loader.loadPDF(new File(pdfFile))) {
        PDFRenderer renderer = new PDFRenderer(document);

        for (int i = 0; i < document.getNumberOfPages(); ++i) {
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            ImageIO.write(renderer.renderImageWithDPI(i, DPI), "gif", out);

            // 将字节数组写入到文件
            try (FileOutputStream fos = new FileOutputStream(outputDir + FileHelper.SEPARATOR + "img-" + i + ".gif")) {
                fos.write(out.toByteArray());
            }
        }

        System.out.println("pdf2img共耗时:" + (System.currentTimeMillis() - old) / 1000.0 + "秒");
    } catch (IOException e) {
        e.printStackTrace();
    }
}

一般一份 PDF 是多页的,于是也会输出多张图片。所以你可以修改里面的文件名生成规则。

相关推荐
GEEKVIP2 小时前
如何在 Windows 10 上恢复未保存/删除的 Word 文档
macos·ios·智能手机·电脑·word·笔记本电脑·iphone
墨染辉5 小时前
10.2 如何解决从复杂 PDF 文件中提取数据的问题?
pdf
shandianchengzi9 小时前
【记录】Excel|Excel 打印成 PDF 页数太多怎么办
pdf·excel
bianshaopeng18 小时前
android 原生加载pdf
android·pdf
卢卡斯23318 小时前
在线PDF怎么转换成JPG图片?分享14种转换操作!
pdf
不写八个19 小时前
Python办公自动化教程(005):Word添加段落
开发语言·python·word
J不A秃V头A1 天前
iTextPDF中,要实现表格中的内容在数据长度超过边框时自动换行
java·pdf
GEEKVIP1 天前
如何修复变砖的手机并恢复丢失的数据
macos·ios·智能手机·word·手机·笔记本电脑·iphone
嘻嘻仙人2 天前
【杂谈一之概率论】CDF、PDF、PMF和PPF概念解释与分析
pdf·概率论·pmf·cdf
资深前端之路2 天前
vue2 将页面生成pdf下载
前端·vue.js·pdf