Word文档转图片功能实现说明

功能概述

在用户下载Word报告的同时,系统会自动将Word文档转换为高清图片并保存到服务器,方便后续使用。

实现原理

Word文档 → PDF文档 → PNG图片(每页一张)

转换流程:
1. 用户请求下载Word报告
2. 系统生成Word文档并返回给用户
3. 后台异步处理:
- 将Word文档保存到服务器
- 将Word转换为PDF
- 将PDF的每一页渲染为PNG图片(300 DPI高清)
- 保存图片到服务器

技术栈

  • Apache POI - Word文档处理
  • XDocReport - Word转PDF
  • Apache PDFBox - PDF转图片
  • Java ImageIO - 图片保存

文件存储结构

F:\file\estate\reports\
├── {uuid}.docx                    # Word原文件
└── images\
    ├── {uuid}_page_1.png         # 第1页图片
    ├── {uuid}_page_2.png         # 第2页图片
    └── {uuid}_page_N.png         # 第N页图片

API接口说明

模糊评价报告下载(支持转图片)

接口地址: GET /admin/stat/report/fuzzyReport

请求参数:
| 参数名 | 类型 | 必填 | 说明 |
|--------|------|------|------|
| checkTaskId | Integer | 是 | 检查任务ID |
| templateId | Integer | 是 | 报告模板ID |
| uuid | String | 否 | 文件唯一标识,传入则保存文件并转换为图片 |

使用示例:

# 仅下载,不保存
curl "http://localhost:8080/admin/stat/report/fuzzyReport?checkTaskId=1&templateId=1"

# 下载并保存+转图片
curl "http://localhost:8080/admin/stat/report/fuzzyReport?checkTaskId=1&templateId=1&uuid=abc123"

配置说明

application.yml 配置

file:
  upload:
    dir: F:\file\estate  # Windows路径
    # dir: /data/uploads  # Linux路径

实际保存路径:
- Word文件:${file.upload.dir}/reports/
- 图片文件:${file.upload.dir}/reports/images/

Maven依赖(已添加)

<!-- PDF to Image conversion -->
<dependency>
    <groupId>org.apache.pdfbox</groupId>
    <artifactId>pdfbox</artifactId>
    <version>2.0.29</version>
</dependency>

核心代码说明

1. 下载方法修改

private void download(XWPFTemplate doc, HttpServletResponse response, String typeName,
                      Integer checkTaskId, Integer templateId, String uuid) throws IOException {
    // ... 生成Word并返回给用户 ...

    // 如果传入uuid,则保存文件并转换为图片
    if(uuid != null && !uuid.isEmpty()) {
        saveFileToServer(docBytes, docName + ".docx", uuid);
        convertWordToImagesAndSave(docBytes, uuid);  // 转换为图片
    }
}

2. Word转图片核心方法

private void convertWordToImagesAndSave(byte[] docBytes, String uuid) {
    // 1. Word → PDF
    XWPFDocument document = new XWPFDocument(new ByteArrayInputStream(docBytes));
    ByteArrayOutputStream pdfOutputStream = new ByteArrayOutputStream();
    PdfConverter.getInstance().convert(document, pdfOutputStream, options);

    // 2. PDF → 图片
    PDDocument pdfDocument = PDDocument.load(pdfBytes);
    PDFRenderer pdfRenderer = new PDFRenderer(pdfDocument);

    // 3. 逐页渲染并保存
    for (int i = 0; i < pageCount; i++) {
        BufferedImage image = pdfRenderer.renderImageWithDPI(i, 300, ImageType.RGB);
        ImageIO.write(image, "PNG", imagePath.toFile());
    }
}

图片质量参数

DPI设置: 300(高清)
- 150 DPI:普通质量,文件较小
- 300 DPI:高清质量,适合打印(当前设置)
- 600 DPI:超高清,文件很大

图片格式: PNG
- 无损压缩
- 支持透明背景
- 适合文档类图片

性能优化建议

1. 异步处理(推荐)

当前实现是同步的,建议改为异步处理:

@Async
public void convertWordToImagesAsync(byte[] docBytes, String uuid) {
    convertWordToImagesAndSave(docBytes, uuid);
}

2. 线程池配置

@Configuration
@EnableAsync
public class AsyncConfig {
    @Bean(name = "imageConversionExecutor")
    public Executor imageConversionExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(2);
        executor.setMaxPoolSize(5);
        executor.setQueueCapacity(100);
        executor.setThreadNamePrefix("image-convert-");
        executor.initialize();
        return executor;
    }
}

3. 缓存机制

对于相同的文档,可以检查是否已存在图片,避免重复转换:

Path imagePath = imageDir.resolve(uuid + "_page_1.png");
if (Files.exists(imagePath)) {
    log.info("图片已存在,跳过转换: {}", uuid);
    return;
}

错误处理

异常不影响用户下载

try {
    convertWordToImagesAndSave(docBytes, uuid);
} catch (Exception e) {
    log.error("Word转图片失败: uuid={}", uuid, e);
    // 不抛出异常,用户仍可正常下载Word文档
}

日志记录

  • INFO级别: 转换进度、成功信息
  • ERROR级别: 转换失败、资源关闭失败
  • WARN级别: 资源关闭警告

测试建议

1. 单元测试

@Test
public void testConvertWordToImages() {
    // 准备测试数据
    byte[] docBytes = Files.readAllBytes(Path.of("test.docx"));
    String uuid = UUID.randomUUID().toString();

    // 执行转换
    reportController.convertWordToImagesAndSave(docBytes, uuid);

    // 验证结果
    Path imagePath = Path.of(REPORT_UPLOAD_DIR, "images", uuid + "_page_1.png");
    assertTrue(Files.exists(imagePath));
}

2. 集成测试

# 1. 调用接口下载并转换
curl -o test.docx "http://localhost:8080/admin/stat/report/fuzzyReport?checkTaskId=1&templateId=1&uuid=test123"

# 2. 检查文件是否生成
ls F:\file\estate\reports\test123.docx
ls F:\file\estate\reports\images\test123_page_*.png

3. 性能测试

  • 测试不同页数文档的转换时间
  • 测试并发转换的性能
  • 测试磁盘空间占用

常见问题

Q1: 转换失败,日志显示字体错误

原因: 系统缺少中文字体

解决方案:
bash # Windows: 确保C:\Windows\Fonts目录有中文字体 # Linux: 安装中文字体 sudo apt-get install fonts-wqy-zenhei fonts-wqy-microhei

Q2: 图片模糊不清晰

原因: DPI设置过低

解决方案: 调整DPI参数
java BufferedImage image = pdfRenderer.renderImageWithDPI(i, 300, ImageType.RGB); // 改为 600 DPI BufferedImage image = pdfRenderer.renderImageWithDPI(i, 600, ImageType.RGB);

Q3: 转换速度慢

原因: 同步处理阻塞主线程

解决方案: 使用异步处理(见性能优化建议)

Q4: 磁盘空间不足

原因: 图片文件占用空间大

解决方案:
1. 降低DPI(300→150)
2. 使用JPEG格式(PNG→JPEG)
3. 定期清理旧文件
4. 使用对象存储(OSS)

扩展功能建议

1. 返回图片URL列表

@GetMapping("/getReportImages")
@ResponseBody
public Result<List<String>> getReportImages(@RequestParam String uuid) {
    List<String> imageUrls = new ArrayList<>();
    Path imageDir = Path.of(REPORT_UPLOAD_DIR, "images");

    try (var stream = Files.list(imageDir)) {
        stream.filter(path -> path.getFileName().toString().startsWith(uuid))
              .sorted()
              .forEach(path -> {
                  String url = "/files/images/" + path.getFileName().toString();
                  imageUrls.add(url);
              });
    }

    return Result.success(imageUrls);
}

2. 支持其他图片格式

// 支持JPEG格式(文件更小)
ImageIO.write(image, "JPEG", imagePath.toFile());

// 支持WebP格式(更高压缩率)
// 需要额外依赖

3. 添加水印

private BufferedImage addWatermark(BufferedImage image, String watermarkText) {
    Graphics2D g2d = image.createGraphics();
    g2d.setFont(new Font("Arial", Font.BOLD, 50));
    g2d.setColor(new Color(255, 0, 0, 50)); // 半透明红色
    g2d.drawString(watermarkText, 100, 100);
    g2d.dispose();
    return image;
}

部署注意事项

Windows部署

file:
  upload:
    dir: F:\file\estate

Linux部署

file:
  upload:
    dir: /data/uploads

确保目录权限:
bash sudo mkdir -p /data/uploads/reports/images sudo chown -R tomcat:tomcat /data/uploads sudo chmod -R 755 /data/uploads

Docker部署

# 挂载数据卷
docker run -v /host/uploads:/data/uploads your-image

监控指标

建议监控以下指标:
- 转换成功率
- 平均转换时间
- 磁盘空间使用率
- 转换队列长度(异步模式)

更新日志

v1.0.0 (2026-01-24)
- ✅ 实现Word转图片基础功能
- ✅ 支持多页文档转换
- ✅ 300 DPI高清输出
- ✅ 完善的异常处理和日志记录
- ✅ 资源自动释放

联系方式

如有问题,请联系开发团队。