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 是多页的,于是也会输出多张图片。所以你可以修改里面的文件名生成规则。

相关推荐
shouchaobao3 小时前
免费PDF工具:PDF转Word/Excel/图片+AI总结+合并拆分+OCR识别,多端无广告!
pdf·word·excel
南风微微吹9 小时前
2026年最新国考《行测》《申论》历年真题及答案PDF电子版(2000-2025年)
pdf·国考
q***017717 小时前
SpringBoot实战(三十二)集成 ofdrw,实现 PDF 和 OFD 的转换、SM2 签署OFD
spring boot·后端·pdf
嗯、.19 小时前
使用Itext9生成PDF水印,兼容不同生成引擎的坐标系(如: Skia、OpenPDF)
java·pdf·itextpdf·openpdf·坐标变换矩阵
拓端研究室21 小时前
专题:2025AI产业全景洞察报告:企业应用、技术突破与市场机遇|附920+份报告PDF、数据、可视化模板汇总下载
大数据·人工智能·pdf
南风微微吹21 小时前
2026年新大纲普通话考试真题题库50套PDF电子版
pdf·普通话
JHC0000001 天前
Python PDF 相关操作
开发语言·python·pdf
CodeCraft Studio1 天前
ABViewer 16全新发布:3D可视化、PDF转DWG、G-code生成全面升级
pdf
lqz19932 天前
根据html导出excel和word
html·word·excel
缺点内向2 天前
C# 中 Word 文档目录的插入与删除指南
开发语言·c#·word·.net