Java实现文档视频缩略图:Spire插件实战
1434 字
7 分钟
Java实现文档视频缩略图:Spire插件实战
📝 本文基于作者实际开发经验,已在项目中成功使用 Spire 插件生成多种格式的缩略图。
背景
很多业务系统需要展示文档和视频的缩略图——比如文件管理系统的列表预览、审批流程中的附件概览等。Java 生态里处理这个问题主要有两条路:
- Apache POI + PDFBox:开源方案,但 Word/PPT 的渲染效果一般,样式兼容性差
- Spire 系列:商业组件,API 简洁,渲染效果好,支持 doc/docx/ppt/pptx/pdf
本文使用 Spire 系列(spire.doc、spire.presentation、spire.pdf)来实现 Word、PPT、PDF 的缩略图生成,视频则使用 JavaCV(FFmpeg)截取第一帧。
依赖配置
Spire 的免费版(Free Spire.Doc/Office/PDF)有页数限制,正式使用建议用商业版。
<!-- Spire.Doc --><dependency> <groupId>e-iceblue</groupId> <artifactId>spire.doc.free</artifactId> <version>5.4.2</version></dependency>
<!-- Spire.Presentation --><dependency> <groupId>e-iceblue</groupId> <artifactId>spire.presentation.free</artifactId> <version>5.4.0</version></dependency>
<!-- Spire.Pdf --><dependency> <groupId>e-iceblue</groupId> <artifactId>spire.pdf.free</artifactId> <version>8.6.0</version></dependency>
<!-- JavaCV(视频截帧) --><dependency> <groupId>org.bytedeco</groupId> <artifactId>javacv-platform</artifactId> <version>1.5.9</version></dependency>注意:Spire 的 jar 包可能无法通过 Maven 公共仓库直接下载,需要手动配置 e-iceblue 的私有仓库,或直接将 jar 包安装到本地 Maven 仓库。
1. Word 缩略图
使用 Document.saveToImages() 将第一页渲染为图片,直接写入 PNG 文件。
private static String wordToImage(String wordFile, String outputImgPath) throws Exception { Document word = new Document(); word.loadFromFile(wordFile); String fileName = getFileName(wordFile); BufferedImage image = word.saveToImages(0, ImageType.Bitmap); String imgUrl = outputImgPath + fileName + (0 + 1) + ".png"; File file = new File(imgUrl); ImageIO.write(image, "PNG", file); log.info("word缩略图获取完成,图片目录:[{}]", imgUrl); return imgUrl;}2. PPT 缩略图
PPT 取第一页幻灯片,用 saveAsImage() 渲染。注意用完后要调用 dispose() 释放资源。
private static String pptToImage(String pptFile, String outputImgPath) throws Exception { Presentation ppt = new Presentation(); ppt.loadFromFile(pptFile); String fileName = getFileName(pptFile); BufferedImage image = ppt.getSlides().get(0).saveAsImage(); String imgUrl = outputImgPath + fileName + (0 + 1) + ".png"; ImageIO.write(image, "PNG", new File(imgUrl)); ppt.dispose(); log.info("ppt缩略图获取完成,图片目录:[{}]", imgUrl); return imgUrl;}3. PDF 缩略图
PDF 同样取第一页,saveAsImage() 的第二个参数指定输出图片类型。
private static String pdfToImage(String pdfFile, String outputImgPath) throws Exception { PdfDocument pdf = new PdfDocument(); pdf.loadFromFile(pdfFile); String fileName = getFileName(pdfFile); BufferedImage image = pdf.saveAsImage(0, PdfImageType.Bitmap); String imgUrl = outputImgPath + fileName + (0 + 1) + ".png"; File file = new File(imgUrl); ImageIO.write(image, "PNG", file); log.info("pdf缩略图获取完成,图片目录:[{}]", imgUrl); return imgUrl;}4. 视频缩略图
视频使用 JavaCV 的 FFmpegFrameGrabber 截取第一帧。如果第一帧为空(某些视频编码问题),会返回空字符串。
private static String videoImage(String videoFile, String outputImgPath) throws FrameGrabber.Exception { FFmpegFrameGrabber ff = FFmpegFrameGrabber.createDefault(videoFile); ff.start(); Frame f = ff.grabImage(); String pngPath = getFileName(videoFile) + ".png"; String resPath = outputImgPath + pngPath; String imageMat = "PNG"; if (null == f || null == f.image) { return ""; } Java2DFrameConverter converter = new Java2DFrameConverter(); BufferedImage bufferedImage = converter.getBufferedImage(f); File output = new File(resPath); try { ImageIO.write(bufferedImage, imageMat, output); } catch (IOException e) { e.printStackTrace(); } log.info("video缩略图获取完成,图片目录:[{}]", resPath); ff.stop(); return resPath;}5. 通用入口方法
根据文件后缀自动路由到对应的处理方法:
public static String generateThumbnail(String file, String outputImgPath) throws Exception { if (!outputImgPath.endsWith(File.separator)) { outputImgPath += File.separator; } String filePath = ""; if (file.endsWith("doc") | file.endsWith("docx")) { filePath = wordToImage(file, outputImgPath); } else if (file.endsWith("ppt") | file.endsWith("pptx")) { filePath = pptToImage(file, outputImgPath); } else if (file.endsWith("pdf")) { filePath = pdfToImage(file, outputImgPath); } else if (file.endsWith("mp4")) { filePath = videoImage(file, outputImgPath); } return filePath;}文件名使用时间戳 + 原始文件名的方式避免冲突:
private static String getFileName(String filePath) { String fileName = new File(filePath).getName(); return System.currentTimeMillis() + "-" + fileName.substring(0, fileName.lastIndexOf("."));}6. Linux 部署踩坑:中文字体缺失
项目部署到 Linux 后,生成的缩略图里中文字符全部显示为方框或空白。原因是 Linux 默认没有安装中文字体,Spire 渲染时找不到对应的字形。
解决方案:安装中文字体。
# 安装 fontconfig 和 mkfontscaleyum install -y fontconfigyum install -y mkfontscale
# 创建字体目录mkdir -p /usr/share/fonts/chinese/chmod -R 775 /usr/share/fonts/chinese/
# 将 Windows 字体(C:\Windows\Fonts)打包上传到服务器,解压到上面的目录# 然后执行以下命令刷新字体缓存cd /usr/share/fontsmkfontscalemkfontdirfc-cache -fv
# 验证中文字体是否生效fc-list :lang=zh安装完成后重启应用,缩略图中的中文就能正常显示了。
完整工具类
import com.spire.doc.Document;import com.spire.doc.documents.ImageType;import com.spire.pdf.PdfDocument;import com.spire.pdf.graphics.PdfImageType;import com.spire.presentation.Presentation;import lombok.extern.slf4j.Slf4j;import org.bytedeco.javacv.FFmpegFrameGrabber;import org.bytedeco.javacv.Frame;import org.bytedeco.javacv.FrameGrabber;import org.bytedeco.javacv.Java2DFrameConverter;
import javax.imageio.ImageIO;import java.awt.image.BufferedImage;import java.io.File;import java.io.IOException;
@Slf4jpublic class ThumbnailUtil {
private static String getFileName(String filePath) { String fileName = new File(filePath).getName(); return System.currentTimeMillis() + "-" + fileName.substring(0, fileName.lastIndexOf(".")); }
private static String wordToImage(String wordFile, String outputImgPath) throws Exception { Document word = new Document(); word.loadFromFile(wordFile); String fileName = getFileName(wordFile); BufferedImage image = word.saveToImages(0, ImageType.Bitmap); String imgUrl = outputImgPath + fileName + (0 + 1) + ".png"; File file = new File(imgUrl); ImageIO.write(image, "PNG", file); log.info("word缩略图获取完成,图片目录:[{}]", imgUrl); return imgUrl; }
private static String pptToImage(String pptFile, String outputImgPath) throws Exception { Presentation ppt = new Presentation(); ppt.loadFromFile(pptFile); String fileName = getFileName(pptFile); BufferedImage image = ppt.getSlides().get(0).saveAsImage(); String imgUrl = outputImgPath + fileName + (0 + 1) + ".png"; ImageIO.write(image, "PNG", new File(imgUrl)); ppt.dispose(); log.info("ppt缩略图获取完成,图片目录:[{}]", imgUrl); return imgUrl; }
private static String pdfToImage(String pdfFile, String outputImgPath) throws Exception { PdfDocument pdf = new PdfDocument(); pdf.loadFromFile(pdfFile); String fileName = getFileName(pdfFile); BufferedImage image = pdf.saveAsImage(0, PdfImageType.Bitmap); String imgUrl = outputImgPath + fileName + (0 + 1) + ".png"; File file = new File(imgUrl); ImageIO.write(image, "PNG", file); log.info("pdf缩略图获取完成,图片目录:[{}]", imgUrl); return imgUrl; }
private static String videoImage(String videoFile, String outputImgPath) throws FrameGrabber.Exception { FFmpegFrameGrabber ff = FFmpegFrameGrabber.createDefault(videoFile); ff.start(); Frame f = ff.grabImage(); String pngPath = getFileName(videoFile) + ".png"; String resPath = outputImgPath + pngPath; if (null == f || null == f.image) { return ""; } Java2DFrameConverter converter = new Java2DFrameConverter(); BufferedImage bufferedImage = converter.getBufferedImage(f); File output = new File(resPath); try { ImageIO.write(bufferedImage, "PNG", output); } catch (IOException e) { e.printStackTrace(); } log.info("video缩略图获取完成,图片目录:[{}]", resPath); ff.stop(); return resPath; }
public static String generateThumbnail(String file, String outputImgPath) throws Exception { if (!outputImgPath.endsWith(File.separator)) { outputImgPath += File.separator; } String filePath = ""; if (file.endsWith("doc") | file.endsWith("docx")) { filePath = wordToImage(file, outputImgPath); } else if (file.endsWith("ppt") | file.endsWith("pptx")) { filePath = pptToImage(file, outputImgPath); } else if (file.endsWith("pdf")) { filePath = pdfToImage(file, outputImgPath); } else if (file.endsWith("mp4")) { filePath = videoImage(file, outputImgPath); } return filePath; }
public static void main(String[] args) throws Exception { String path = generateThumbnail("D:\\desktop\\test\\video.mp4", "D:\\desktop\\test\\img"); System.out.println(path); }}相关推荐
- SpringBoot配置文件全局变量:多环境部署秘钥管理 - SpringBoot 配置管理
- SSM框架访问静态资源:SpringMVC配置详解 - Java Web 开发
- RabbitMQ从入门到实战:消息队列核心用法详解 - Java 中间件
文章分享
如果这篇文章对你有帮助,欢迎分享给更多人!
Java实现文档视频缩略图:Spire插件实战
https://blog.wmovie.site/posts/java-document-thumbnails/ 相关文章 智能推荐
1
SSM框架访问静态资源:SpringMVC配置详解
开发笔记 SSM框架中配置静态资源访问的方法,解决SpringMVC拦截静态资源导致样式丢失的问题。
2
RabbitMQ从入门到实战:消息队列核心用法详解
运维自动化 SpringBoot项目中RabbitMQ的使用指南,包括交换机类型、监听队列的两种方式及完整配置示例。
3
SpringBoot配置文件全局变量:多环境部署秘钥管理
开发笔记 SpringBoot中使用配置文件全局变量的方法,实现多环境部署时秘钥和配置的动态切换,避免重复打包。
4
Kindle传书完全指南:Calibre管理任意格式电子书
开发笔记 Kindle传书终极教程,使用Calibre管理epub、mobi、azw3、pdf等任意格式电子书,支持批量转换和推送。
5
SSE服务器推送:实时网络传输协议详解与实战
软路由与网络 SSE是基于HTTP的轻量级单向传输协议,允许服务器主动向客户端推送实时数据。本文介绍SSE的客户端和服务端实现方式。
随机文章 随机推荐