JAVA实现PDF转HTML文档

本文是将PDF文档转PNG图片,然后进行图片拼接,拼接后的图片转为base64字符串,然后拼接html文档(再写入html文件)。

引入maven依赖

<!-- https://mvnrepository.com/artifact/org.apache.pdfbox/pdfbox --><dependency><groupId>org.apache.pdfbox</groupId><artifactId>pdfbox</artifactId><version>2.0.12</version></dependency>

工具实现类

package cn.yueworld.pms.web.util;import cn.yueworld.framework.tools.exception.LogicException;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.rendering.PDFRenderer;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sun.misc.BASE64Encoder;import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.net.URL;/*** PDF文档转HTML文档** @author zkg* @since 2024/6/11 16:45*/
public class PdfConvertHtmlUtil {/*** 日志对象*/private static Logger logger = LoggerFactory.getLogger(PdfConvertHtmlUtil.class);/*** pdf转图片** @param pdfUrl pdf路径* @return BufferedImage 图片*/public static BufferedImage pdfToImage(String pdfUrl) {PDDocument doc = null;try {// 本地文件// File file = new File("C:\\Users\\Dell\\Downloads\\测试.pdf");// inputStream = new FileInputStream(file);logger.info("解析pdf+pdfUrl:" + pdfUrl);URL url = new URL(pdfUrl);InputStream inputStream = url.openStream();doc = PDDocument.load(inputStream);PDFRenderer renderer = new PDFRenderer(doc);int pageCount = doc.getNumberOfPages();BufferedImage image = null;for (int i = 0; i < pageCount; i++) {if (image != null) {image = combineBufferedImages(image, renderer.renderImageWithDPI(i, 144));}if (i == 0) {image = renderer.renderImageWithDPI(i, 144); // Windows native DPI}// BufferedImage srcImage = resize(image, 240, 240);//产生缩略图}return combineBufferedImages(image);} catch (IOException e) {e.printStackTrace();} finally {try {if (doc != null) {doc.close();}} catch (IOException e) {e.printStackTrace();}}return null;}/*** BufferedImage拼接处理,添加分割线** @param images 文件* @return BufferedImage 添加分割线*/public static BufferedImage combineBufferedImages(BufferedImage... images) {int height = 0;int width = 0;for (BufferedImage image : images) {//height += Math.max(height, image.getHeight());height += image.getHeight();width = image.getWidth();}BufferedImage combo = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);Graphics2D g2 = combo.createGraphics();int x = 0;int y = 0;for (BufferedImage image : images) {//int y = (height - image.getHeight()) / 2;g2.setStroke(new BasicStroke(2.0f));// 线条粗细g2.setColor(new Color(193, 193, 193));// 线条颜色g2.drawLine(x, y, width, y);// 线条起点及终点位置g2.drawImage(image, x, y, null);//x += image.getWidth();y += image.getHeight();}return combo;}/*** 通过Base64创建HTML文件并输出html文件** @param base64  文件的base64* @param htmlUrl html保存路径*/public static void createHtmlByBase64(String base64, String htmlUrl) {StringBuilder stringHtml = new StringBuilder();PrintStream printStream = null;try {// 打开文件printStream = new PrintStream(new FileOutputStream(htmlUrl));} catch (FileNotFoundException e) {e.printStackTrace();}// 输入HTML文件内容stringHtml.append("<html><head>");stringHtml.append("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">");stringHtml.append("<title></title>");stringHtml.append("</head>");stringHtml.append("<body style=\"\r\n" + "    text-align: center;\r\n" + "    background-color: #C1C1C1;\r\n" + "\">");stringHtml.append("<img src=\"data:image/png;base64," + base64 + "\" />");stringHtml.append("<a name=\"head\" style=\"position:absolute;top:0px;\"></a>");//添加锚点用于返回首页stringHtml.append("<a style=\"position:fixed;bottom:10px;right:10px\" href=\"#head\">回到首页</a>");stringHtml.append("</body></html>");try {// 将HTML文件内容写入文件中printStream.println(stringHtml.toString());} catch (Exception e) {e.printStackTrace();} finally {if (printStream != null) {printStream.close();}}}/*** 图片转为base64编码** @param bufferedImage 图片* @return base64编码*/public static String bufferedImageToBase64(BufferedImage bufferedImage) {ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();String png_base64 = "";try {ImageIO.write(bufferedImage, "png", byteArrayOutputStream);// 写入流中byte[] bytes = byteArrayOutputStream.toByteArray();// 转换成字节BASE64Encoder encoder = new BASE64Encoder();// 转换成base64串 删除 \r\npng_base64 = encoder.encodeBuffer(bytes).trim().replaceAll("\n", "").replaceAll("\r", "");} catch (IOException e) {e.printStackTrace();}return png_base64;}/*** 将图片的base64编码替换到html文件里面** @param htmlUrl 文件路径* @param base64  图片* @return html*/public static Document htmlReplaceTag(String htmlUrl, String base64) {try {// 读取文件// File file = new File(htmlUrl);// Document document = Jsoup.parse(file, "UTF-8");logger.info("解析html+htmlUrl" + htmlUrl);// 使用Jsoup.connect方法获取Document对象Document document = Jsoup.connect(htmlUrl).get();logger.info("替换元素内容开始:" + document);// 通过ID获取要替换的元素Element oldTag = document.getElementById("pdfFileId");if (oldTag != null) {// 替换元素内容if (base64 != null) {// 创建新标签Element newTag = document.createElement("img");// 设置图片的idnewTag.attr("id", "pdfFileId");// 设置图片的属性newTag.attr("src", "data:image/png;base64," + base64);// 替换旧标签oldTag.replaceWith(newTag);} else {oldTag.remove();}logger.info("替换元素内容结束:" + document);}// 保存修改后的HTML文件document.outputSettings().charset("UTF-8");document.outputSettings().prettyPrint(true);// 写到本地// FileWriter fileWriter = new FileWriter(new File("C:\\Users\\Dell\\Downloads\\测试.html"));// fileWriter.write(document.outerHtml());// fileWriter.close();return document;} catch (Exception e) {e.printStackTrace();logger.error("将图片的base64编码替换到html文件里面失败:" + e.getMessage());throw new LogicException("将图片的base64编码替换到html文件里面失败");}}/*** html + pdf** @param htmlUrl 文件路径* @param pdfUrl  图片* @return html*/public static Document htmlAddPdf(String htmlUrl, String pdfUrl) {try {String base64_png = null;if (pdfUrl != null) {// pdf转图片BufferedImage bufferedImage = pdfToImage(pdfUrl);// 图片转为base64编码base64_png = bufferedImageToBase64(bufferedImage);}// 将图片的base64编码替换到html文件里面return htmlReplaceTag(htmlUrl, base64_png);} catch (Exception e) {e.printStackTrace();logger.error("pdf文件转换失败:" + e.getMessage());throw new LogicException("pdf文件转换失败:" + e.getMessage());}}
}

测试Demo

public static void main(String[] args) {// PDF文件URLString pdfUrl = "https://geli-dev.yueworld.cn:8060/group1/M00/00/47/wKh5GWZfvn6AILBZAASNWOGlbkI479.pdf";// HTML文件路径String htmlUrl = "https://geli-dev.yueworld.cn:8060/cm_web/print/cm_Zlcontract001/#/cm_Zlcontract001?conId=2371";Document document = htmlAddPdf(htmlUrl, pdfUrl);System.out.println("结果:" + document);}

可以是在线的pfd、html,也可以是本地的pdf和html,两种方法工具类里面都有。

第三方库Jsoup

其中在线的html需要使用第三方库Jsoup,Jsoup是一个开源的Java库,它提供了简单和方便的API来处理HTML文档。

你可以使用以下代码添加Jsoup依赖项到你的项目中:

依赖

<dependency><groupId>org.jsoup</groupId><artifactId>jsoup</artifactId><version>1.13.1</version>
</dependency>

下面是一个使用Jsoup获取网页HTML数据的示例代码:

import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;public class HtmlFetcher {public static void main(String[] args) {try {// 使用Jsoup.connect方法获取Document对象Document doc= Jsoup.connect(htmlUrl).get();String htmlData = doc.html();System.out.println(htmlData);} catch (Exception e) {e.printStackTrace();}}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/861713.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

首次线下联合亮相!灵途科技携手AEye、ATI亮相2024 EAC 易贸汽车产业大会

6月22日&#xff0c;2024 EAC 易贸汽车产业大会在苏州国际博览中心圆满落幕&#xff0c;泛自动驾驶领域光电感知专家灵途科技携手自适应高性能激光雷达解决方案全球领导者AEye公司&#xff08;NASDAQ:LIDR&#xff09;及光电器件规模化量产巨头Accelight Technologies&#xff…

【单片机开发--使用循环缓冲区接受can数据帧,读写数据到内存】

双指针读写数组需要考虑的问题 使用双指针循环读写数值可能会遇到的问题&#xff1a; 初始值&#xff0c;边界值问题。 topbottom0 top往后移使用top ( top moveSize ) % buffSize bottom往后移使用bottom ( bottom moveSize ) % buffSize。 top指向的位置没有数据&…

第十七站:Java钛金——高性能计算的坚固基石

Java NIO&#xff1a;非阻塞式I/O的革命 Java NIO&#xff0c;全称为New Input/Output&#xff0c;是Java平台对传统阻塞式I/O模型的一次重大革新。NIO引入了Channel和Buffer的概念&#xff0c;允许程序在不等待I/O操作完成的情况下继续执行其他任务&#xff0c;从而极大地提升…

量块检定校准中,如何调整好校准所需的温度条件?

量块是计量中常用的标准件&#xff0c;在日常使用中可以作为各类仪器校准中的辅助工具&#xff0c;而量块自身如果进行检定校准&#xff0c;其校准过程中温度的条件就是需要多次进行调控&#xff0c;因为量块的校准需要在恒温环境下进行&#xff0c;量块的精确度和实验室环境的…

触摸屏与罗克韦尔AB PLC之间 ModbusTCP/IP无线以太网通讯实例

在实际系统中&#xff0c;同一个车间里分布多台PLC&#xff0c;通过触摸屏人机界面集中控制。通常所有设备距离在几十米到上百米不等。在有通讯需求的时候&#xff0c;如果布线的话&#xff0c;工程量较大耽误工期&#xff0c;这种情况下比较适合采用无线通信方式。本方案以组态…

虚拟机查看端口占用情况

ps -aux | grep 8888 ps aux | grep 8888命令用于查找并显示所有包含字符串"8888"的进程。具体来说&#xff1a; ps命令用于列出当前系统上的进程。 aux选项是常见的用法&#xff0c;它显示所有用户的所有进程&#xff0c;并显示详细的进程信息。 | grep 8888将ps命令…

JAVA学习-练习试用Java实现“二叉树的中序遍历”

问题&#xff1a; 给定一个二叉树的根节点 root &#xff0c;返回它的 中序 遍历。 示例 1&#xff1a; 输入&#xff1a;root [1,null,2,3] 输出&#xff1a;[1,3,2] 示例 2&#xff1a; 输入&#xff1a;root [] 输出&#xff1a;[] 示例 3&#xff1a; 输入&…

操作系统面试篇一

很多读者抱怨计算操作系统的知识点比较繁杂&#xff0c;自己也没有多少耐心去看&#xff0c;但是面试的时候又经常会遇到。所以&#xff0c;我带着我整理好的操作系统的常见问题来啦&#xff01;这篇文章总结了一些我觉得比较重要的操作系统相关的问题比如 用户态和内核态、系统…

C++一文讲透thread中的detach和join的差别

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、thread详解二、线程何时运行三、线程启动方式1.join2.detach 总结 前言 无论哪种语言线程在绝大多数项目中都是会用到的&#xff0c;C也一样&#xff0c;C…

昇思25天学习打卡营第9天 | 静态图加速

内容介绍&#xff1a; AI编译框架分为两种运行模式&#xff0c;分别是动态图模式以及静态图模式。MindSpore默认情况下是以动态图模式运行&#xff0c;但也支持手工切换为静态图模式。两种运行模式的详细介绍如下&#xff1a; 动态图模式&#xff1a; 动态图的特点是计算图的…

【Docker项目实战篇】Docker部署PDF多功能工具Stirling-PDF

【Docker项目实战篇】Docker部署PDF多功能工具Stirling-PDF 前言一、Stirling-PDF介绍1.1 Stirling-PDF简介1.2 Stirling-PDF功能 二、本次实践规划2.1 本地环境规划2.2 本次实践介绍 三、本地环境检查3.1 检查Docker服务状态3.2 检查Docker版本3.3 检查docker compose 版本 四…

详解Elastic Search高速搜索背后的秘密:倒排索引

&#x1f3ac; 鸽芷咕&#xff1a;个人主页 &#x1f525; 个人专栏: 《C干货基地》《粉丝福利》 ⛺️生活的理想&#xff0c;就是为了理想的生活! 引入 全文搜索属于最常见的需求&#xff0c;开源的 Elasticsearch &#xff08;以下简称 Elastic&#xff09;是目前全文搜索引…

Python应用开发——30天学习Streamlit Python包进行APP的构建(10)

st.map 显示一张叠加了散点图的地图。 它是 st.pydeck_chart 的包装器&#xff0c;用于在地图上快速创建散点图表&#xff0c;并具有自动居中和自动缩放功能。 使用该命令时&#xff0c;Mapbox 会提供地图瓦片来渲染地图内容。请注意&#xff0c;Mapbox 是第三方产品&#x…

海云安参编《数字安全蓝皮书 》正式发布并入选《2024中国数字安全新质百强》荣膺“先行者”

近日&#xff0c;国内数字化产业第三方调研与咨询机构数世咨询正式发布了《2024中国数字安全新质百强》&#xff08;以下简称百强报告&#xff09;。海云安凭借在开发安全领域的技术创新力及市场影响力入选百强报告“新质百强先行者” 本次报告&#xff0c;数世咨询经过对国内8…

AJAX 实例:深入解析与实战应用

AJAX 实例:深入解析与实战应用 引言 AJAX(Asynchronous JavaScript and XML)是一种无需重新加载整个网页的情况下,能够更新部分网页的技术。自2005年提出以来,AJAX已成为现代Web开发的重要组成部分,极大地提升了用户体验和网页性能。本文将通过一系列实例,深入解析AJA…

用Verilog实现4位计数器(时序逻辑)

用Verilog实现4位计数器。&#xff08;时序逻辑&#xff09; 实验目的&#xff1a; 通过用Verilog实现4位计数器&#xff0c;进一步熟悉Verilog的语法和时序逻辑电路。 实验描述&#xff1a; 输入&#xff1a; Clock&#xff1a;如果计数器enable信号为1&#xff0c;那么在…

多功能气象传感器的工作原理

TH-WQX9多功能气象传感器是一种集成了多种传感器技术的气象观测装置&#xff0c;旨在同时测量和监测大气中的多个气象要素&#xff0c;以提供全面、准确的气象信息。以下是关于多功能气象传感器的详细介绍&#xff1a; 技术原理 多功能气象传感器采用多种传感器技术相结合&…

深入理解Git:rebase与merge

在Git的版本控制中&#xff0c;rebase和merge是两个至关重要的操作&#xff0c;它们用于整合不同分支的修改。然而&#xff0c;很多开发者在使用时容易混淆&#xff0c;今天我们就来详细解析一下两者的区别、优缺点&#xff0c;并通过实战代码来演示它们的用法。 一、rebase与…

Linux(Ubuntu)下源码开发整个流程完成版本(下载->编译->模拟器运行)

写这篇文章没别的意思, 年纪大了记性不好, 这次工作中下载,编译遇到了一些之前没遇到的问题,所以就所幸记录一下, 以便日后能快速查阅 好了, 正题开始 首先我们下载AOSP源代码开始 AOSP源代码下载 首先找到官网https://source.android.google.cn/ 进入后最上面点击获取源代…

day01-项目介绍及初始化-登录页

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 day01-项目介绍及初始化-登录页一、人力资源项目介绍1.1项目架构和解决方案主要模块解决的问题 二、拉取项目基础代码1.引入库2.升级core-js版本到3.25.5按照完整依…