Word 文档转换 PDF、图片

2023-09-18 22:33:10

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

Word 转 PDF

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

Aspose 方案

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

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

<!-- 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节点:

<manifestEntries>
    <!--MANIFEST.MF 中 Class-Path 加入资源文件目录 -->
    <Class-Path>lib/aspose-words-15.8.jar</Class-Path>
</manifestEntries>

新增于 pom.xml 的<plugins>位置如图:
在这里插入图片描述
拷贝 jar 包,除了 runtime 的还有刚新加的 system 包,新增一个copy-dependencies2

<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>位置如图:
在这里插入图片描述

转换程序

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 方案

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

转换程序

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。

<!-- PDF2Img -->
<dependency>
    <groupId>org.apache.pdfbox</groupId>
    <artifactId>pdfbox</artifactId>
    <version>3.0.0</version>
</dependency>

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

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

更多推荐

如何辨认是否是高防服务器?

因为现在高防服务器比较出名,很多IDC服务器商都标榜自己的服务器是高防服务器,那我们怎么辨别服务器商说的高防服务器是否是真正的高防服务器呢?今天小编就告诉大家几点辨认是否是高防服务器的小要点。向选择好的服务器商要一下高防服务器的IP,然后通过简单的测试来看一看,也就是ping指令(用来测试网络连接是否正常)来检查,一般

如何使用插件扩展Vue的功能

Vue是一款流行的前端JavaScript框架,它的核心库提供了许多强大的功能,但有时我们需要额外的功能来满足特定需求。这时,使用插件来扩展Vue的功能是一个很好的选择。本文将详细介绍如何使用插件来扩展Vue的功能,包括创建、注册和使用插件。Vue提供了强大的插件系统,供大家来扩展项目功能。开发者可以自由的使用公开的第

Python+pytest接口自动化之参数关联

一、什么是参数关联?参数关联,也叫接口关联,即接口之间存在参数的联系或依赖。在完成某一功能业务时,有时需要按顺序请求多个接口,此时在某些接口之间可能会存在关联关系。比如:B接口的某个或某些请求参数是通过调用A接口获取的,即需要先请求A接口,从A接口的返回数据中拿到需要的字段值,在请求B接口时作为请求参数传入。二、有哪些

Hoeffing不等式

在李航老师的统计学习方法(第一版中)Hoeffing不等式Hoeffing不等式Hoeffing不等式是这样子给出的设X1,X2,...,XNX_1,X_2,...,X_NX1​,X2​,...,XN​是独立随机变量,且Xi∈[ai,bi],i=1,2,...,N;SN=∑i=1NXiX_i\in[a_i,b_i],i

VMware Fusion 13在M2芯片的Mac上安装 Windows 11

首先需要下载Windows11镜像以下给出一种官方方法,当然也可以自己去网上搜索,有很多资源注册微软账号使用注册的账号登录访问:https://www.microsoft.com/en-us/windowsinsider/register使用登录的账号注册Windows11InsiderProgram看到以下页面,就是

【2023华为杯A题】WLAN网络信道接入机制建模(代码、思路.....)

💥💥💞💞欢迎来到本博客❤️❤️💥💥🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。⛳️座右铭:行百里者,半于九十。📋📋📋本文目录如下:🎁🎁🎁目录💥1背景1.1分布式信道接入和二进制指数退避1.2基于Markovchain的DCF机制建模和系统性能分析📚2WLAN组

Apache shenyu,Java 微服务网关的首选

微服务网关的产生背景当我们系统复杂度越来越高,团队协作效率越来越低时,我们通常会想到通过"拆分"来应对,这是典型的"化繁为简,分而治之"的思想。在落地过程中,我们通常会引入"SOA"或者"微服务"架构手段,如下图所示:技术更新日新月异,站在当下去看,“微服务”、“API网关”、“云原生”、“servicemesh”…这

CFCA证书 申请 流程(一)

CFCA证书CFCA证书是指由中国金融认证中心颁发的证书,包括普通数字证书、服务器数字证书和预植证书等,目前,各大银行和金融机构都会使用CFCA颁发的证书作为官网的HTTPS证书、手机银行等APP使用的证书以及USB-KEY(U盾)内置的证书。在案例中包括中国工商银行、中国民生银行、中国光大银行、中信银行、兴业银行、中

NSS [西湖论剑 2022]real_ez_node

NSS[西湖论剑2022]real_ez_node考点:ejs原型链污染、NodeJS中Unicode字符损坏导致的HTTP拆分攻击。开题。附件start.sh。flag位置在根目录下/flag.txtapp.js(这个没多大用)varcreateError=require('http-errors');varexpr

企业微信-通用开发参数回调设置

公司业务需要开发企业微信,注册三方服务商审核通过后,开始配置开发信息。本篇中记录在调试url验证中遇到错误及解决方式。目录准备工作下载php加解密库下载文件说明设置白名单设置路径参数说明设置ip回调处理回调类型:1、Get类型2、Post类型Get回调实现设置路由控制器业务层处理配置开发信息遇到问题发现问题解决方案准备

学习路之工具--SecureCRT的下载、安装

百度盘:链接:https://pan.baidu.com/s/1r3HjEj053cKys54DTqLM4A?pwd=gcac提取码:gcac复制这段内容后打开百度网盘手机App,操作更方便哦感谢大佬简单介绍下SecureCRTSecureCRT是一款支持SSH(SSH1和SSH2)的终端仿真程序,简单地说是Windo

热文推荐