【PDFBox】PDFBox操作PDF文档之添加本地图片、添加网络图片、图片宽高自适应、图片水平垂直居中对齐

这篇文章,主要介绍PDFBox操作PDF文档之添加本地图片、添加网络图片、图片宽高自适应、图片水平垂直居中对齐。

目录

一、PDFBox操作图片

1.1、添加本地图片

(1)案例代码

(2)运行效果

(3)方法介绍

1.2、添加网络图片

(1)案例代码

(2)运行效果

1.3、图片宽高自适应(图片缩放)

(1)图片缩放代码

(2)运行效果

1.4、读取图片

(1)案例代码

(2)运行效果


一、PDFBox操作图片

PDFBox可以向PDF文档中添加图片对象,使用PDImageXObject表示一个图片对象,对PDF文档的内容进行操作,都需要借助于PDPageContentStream页面内容流对象来完成,PDFBox将每一个PDF页面中的所有文本、图片、表单等内容看作一个流,通过流的方式来完成内容的添加、删除、修改等操作。这里首先介绍如何使用PDFBox添加图片对象到PDF文档里面。

1.1、添加本地图片

(1)案例代码

添加本地图片,也就是读取当前磁盘中的图片,然后将这个图片写入到PDPageContentStream页面内容流里面,案例代码如下:

package pdfbox.demo.image;import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.common.PDRectangle;
import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;/*** @version 1.0.0* @Date: 2023/7/15 14:51* @Author ZhuYouBin* @Description: PDFBox操作图片*/
public class PDFBoxImageUtil {/*** 将给定路径的图片,保存到pdf文件里面* @param imgPath 图片路径* @param destPdf 生成的pdf文件路径* @return 返回生成的pdf文件路径*/public static String generateImageToPdf(String imgPath, String destPdf) {try {// 1、创建PDF文档对象PDDocument doc = new PDDocument();// 2、创建Page页面对象PDPage page = new PDPage(PDRectangle.A4);// 3、创建图片对象PDImageXObject image = PDImageXObject.createFromFile(imgPath, doc);// 4、创建页面内容流,指定操作哪个文档中的哪个页面PDPageContentStream stream = new PDPageContentStream(doc, page);stream.drawImage(image, 10, 10); // 绘制图片到PDF页面里面stream.close(); // 关闭页面内容流doc.addPage(page); // 添加页面到PDF文档doc.save(destPdf); // 保存PDF文档doc.close(); // 关闭PDF文档} catch (Exception e) {e.printStackTrace();}return destPdf;}public static void main(String[] args) {String imgPath = "E:\\demo\\001.jpg";String destPdf = "E:\\demo\\img.pdf";generateImageToPdf(imgPath, destPdf);}
}

(2)运行效果

(3)方法介绍

PDImageXObject类中提个了一些静态方法,常见的有下面这些:

  • createFromFile(imagePath,doc)方法:采用File文件的方式读取本地磁盘中的图片。
    • imagePath参数:图片的路径。
    • doc参数:PDF文档对象。
  • getImage()方法:返回BufferedImage图片对象。
  • getSuffix()方法:返回图片的后缀类型,例如:jpg、png等。

1.2、添加网络图片

PDFBox中是没有提供读取网络图片的方法,但是可以采用下面这种方式实现读取网络图片的功能,思路如下:

  • 第一步:使用URL对象将网络图片下载到本地磁盘上。
  • 第二步:使用createFromFile()方法从本地磁盘读取刚刚下载的网络图片。

(1)案例代码

package pdfbox.demo.image;import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.common.PDRectangle;
import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
import java.util.UUID;/*** @version 1.0.0* @Date: 2023/7/15 15:01* @Author ZhuYouBin* @Description: PDFBox操作图片,添加网络图片到PDF文档*/
public class PDFBoxImageUtil {/*** 将给定路径的图片,保存到pdf文件里面* @param imgPath 图片路径* @param destPdf 生成的pdf文件路径* @return 是否生成成功*/public static String generateImageToPdf(String imgPath, String destPdf) {try {// 1、创建PDF文档对象PDDocument doc = new PDDocument();// 2、创建Page页面对象PDPage page = new PDPage(PDRectangle.A4);// 3、创建图片对象PDImageXObject image;boolean isTemp = false;String tempPath = null;if (imgPath.startsWith("http://") || imgPath.startsWith("https://")) {isTemp = true;tempPath = downloadImage(imgPath, null);image = PDImageXObject.createFromFile(tempPath, doc);} else {image = PDImageXObject.createFromFile(imgPath, doc);}// 4、创建页面内容流,指定操作哪个文档中的哪个页面PDPageContentStream stream = new PDPageContentStream(doc, page);stream.drawImage(image, 10, 10); // 绘制图片到PDF页面里面stream.close(); // 关闭页面内容流doc.addPage(page); // 添加页面到PDF文档doc.save(destPdf); // 保存PDF文档doc.close(); // 关闭PDF文档// 图片添加成功之后需要删除本地临时文件if (isTemp) {new File(tempPath).delete();}} catch (Exception e) {e.printStackTrace();}return destPdf;}/*** 下载网络图片到本地* @param imgPath 网络图片地址* @param fileName 文件名称* @return 返回本地图片的临时路径*/public static String downloadImage(String imgPath, String fileName) {try {URLConnection conn = new URL(imgPath).openConnection();String contentType = conn.getContentType();System.out.println(contentType);// 创建临时文件目录保存图片File file = new File("temp");if (!file.exists() && !file.mkdirs()) {throw new RuntimeException("临时目录创建失败");}if (fileName == null || fileName.trim().equals("")) {fileName = UUID.randomUUID().toString();}InputStream is = conn.getInputStream();byte[] data = new byte[1024];int len;// 下载文件到本地临时目录switch (contentType) {case "image/jpeg":fileName += ".jpeg"; break;case "image/gif": fileName += ".gif"; break;case "image/webp":case "image/png": fileName += ".png"; break;}fileName = file.getAbsolutePath() + File.separator + fileName;FileOutputStream fos = new FileOutputStream(fileName);while ((len = is.read(data)) != -1) {fos.write(data, 0, len);}fos.close();is.close();} catch (Exception e) {e.printStackTrace();}return fileName;}public static void main(String[] args) {String imgPath = "https://www.toopic.cn/public/uploads/small/1658043938262165804393852.jpg";String destPdf = "E:\\demo\\img.pdf";generateImageToPdf(imgPath, destPdf);}
}

(2)运行效果

1.3、图片宽高自适应(图片缩放)

前面已经能够将图片添加到PDF文档中了,但是可以发现,我们添加的图片尺寸太大的时候,超过PDF文档部分就会被遮挡,如何解决这个问题呢???对于这个问题,可以采用缩放图片的方式来解决,思路如下所示:

  • 第一步:获取图片的实际宽度、高度(JDK中获取到的图片宽高单位是【px】,需要将【px】转换成【pt】单位,转换规则:1pt = 3/4 px)。
  • 第二步:获取到PDF文档的宽度、高度(PDFBox中获取到的宽度、高度是采用【pt】作为单位的)。
  • 第三步:图片的实际宽高和PDF文档的宽高进行比较,计算缩放比例。

(1)图片缩放代码

package pdfbox.demo.image;import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.common.PDRectangle;
import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
import java.util.UUID;/*** @version 1.0.0* @Date: 2023/7/15 15:11* @Author ZhuYouBin* @Description: PDFBox操作图片,图片宽高自动缩放*/
public class PDFBoxImageUtil {/*** 将给定路径的图片,保存到pdf文件里面** @param imgPath 图片路径* @param destPdf 生成的pdf文件路径* @return 返回生成的pdf文件路径*/public static boolean generateImageToPdf(String imgPath, String destPdf) {try {// 1、创建PDF文档对象PDDocument doc = new PDDocument();// 2、创建Page页面对象PDPage page = new PDPage(PDRectangle.A4);// 3、创建图片对象PDImageXObject image;if (imgPath.startsWith("http://") || imgPath.startsWith("https://")) {String tempPath = downloadImage(imgPath, null);image = PDImageXObject.createFromFile(tempPath, doc);imgPath = tempPath;} else {image = PDImageXObject.createFromFile(imgPath, doc);}// 4、创建页面内容流,指定操作哪个文档中的哪个页面PDPageContentStream stream = new PDPageContentStream(doc, page);// 获取图片的宽高float[] imageWH = getImageWH(imgPath, page.getMediaBox());stream.drawImage(image, imageWH[0], imageWH[1], imageWH[2], imageWH[3]); // 绘制图片到PDF页面里面stream.close(); // 关闭页面内容流doc.addPage(page); // 添加页面到PDF文档doc.save(destPdf); // 保存PDF文档doc.close(); // 关闭PDF文档return true;} catch (Exception e) {e.printStackTrace();}return false;}/*** 获取图片的宽度、高度,单位是【pt】** @param imgPath 图片路径* @param box     PDF文档页面矩形区域对象,可以获取到矩形区域的宽高* @return 返回缩放之后的图片宽高*/public static float[] getImageWH(String imgPath, PDRectangle box) {try {File file = new File(imgPath);InputStream is = new FileInputStream(file);// 判断是不是网络上的图片if (imgPath.startsWith("http://") || imgPath.startsWith("https://")) {is = new URL(imgPath).openStream();}BufferedImage bi = ImageIO.read(is);// px 转换成 pt 单位float xAxis;float yAxis;int w = bi.getWidth();int h = bi.getHeight();float width = (float) (w * 3.0 / 4); // 这里是因为 1pt = 3/4 px,pt和px单位转换float height = (float) (h * 3.0 / 4);float pw = box.getWidth() - 60; // 这里减不减60没啥关系,只是设置一下空白间距float ph = box.getHeight() - 60; // 这里减不减60没啥关系,只是设置一下空白间距if (width > pw) {float scale = pw / width;  // 缩放比列width = pw; // 宽度等于页面宽度height = height * scale; // 高度自动缩放} else {float scale = ph / height;  // 缩放比列height = ph; // 高度等于页面高度width = width * scale;  // 宽度自动缩放}// 计算图片在X、Y轴上的显示位置xAxis = (box.getWidth() - width) / 2; // X轴居中对齐
//            yAxis = box.getHeight() - height - 10; // 距离页面顶部10个ptyAxis = (box.getHeight() - height) / 2; // Y轴垂直居中对齐return new float[]{xAxis, yAxis, width, height};} catch (Exception e) {e.printStackTrace();}return new float[]{0, 0, 0, 0};}/*** 下载网络图片到本地* @param imgPath 网络图片地址* @param fileName 文件名称* @return 返回本地图片的临时路径*/public static String downloadImage(String imgPath, String fileName) {try {URLConnection conn = new URL(imgPath).openConnection();String contentType = conn.getContentType();// 创建临时文件目录保存图片File file = new File("temp");if (!file.exists() && !file.mkdirs()) {throw new RuntimeException("临时目录创建失败");}if (fileName == null || fileName.trim().equals("")) {fileName = UUID.randomUUID().toString().replaceAll("-", "");}InputStream is = conn.getInputStream();byte[] data = new byte[1024];int len;// 下载文件到本地临时目录switch (contentType) {case "image/jpeg":fileName += ".jpeg"; break;case "image/gif": fileName += ".gif"; break;case "image/webp":case "image/png": fileName += ".png"; break;}fileName = file.getAbsolutePath() + File.separator + fileName;FileOutputStream fos = new FileOutputStream(fileName);while ((len = is.read(data)) != -1) {fos.write(data, 0, len);}fos.close();is.close();} catch (Exception e) {e.printStackTrace();}return fileName;}public static void main(String[] args) {String imgPath = "https://www.toopic.cn/public/uploads/small/1658043938262165804393852.jpg";String destPdf = "E:\\demo\\img.pdf";generateImageToPdf(imgPath, destPdf);}
}

(2)运行效果

1.4、读取图片

PDFBox也可以从PDF文档中读取图片,然后将其保存到本地磁盘中,保存图片可以使用JDK中提供的ImageIO类,这个类中提供了一个write()方法,可以将图片对象写入到File文件里面。

(1)案例代码

package pdfbox.demo.image;import org.apache.pdfbox.cos.COSName;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDResources;
import org.apache.pdfbox.pdmodel.graphics.PDXObject;
import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;/*** @version 1.0.0* @Date: 2023/7/15 15:11* @Author ZhuYouBin* @Description: PDFBox操作图片,从PDF文档中【读取图片】,并且保存到本地*/
public class PDFBoxImageUtil {/*** 从给定的pdf文档里面,获取指定页面中的所有图片,并且保存到本地目录下* <p>*     pdf文档中的图片都是BASE64编码,我们能够获取到的也就只能是图片对应的BASE64字符串。*     所以,还需要将图片的BASE64字符串编码转换成对应的图片文件* </p>* @param pdfPath PDF文档路径* @param imagePath 生成的图片路径以及名称* @param pageNum 获取第几页的图片* @return 返回提取的图片本地路径*/public static String readerImageFromPdf(String pdfPath, String imagePath, int pageNum) {try {// 1、加载PDF文档PDDocument doc = PDDocument.load(new File(pdfPath));// 2、遍历所有Page页面,找到指定的page页面获取图片int pages = doc.getNumberOfPages();for (int i = 0; i < pages; i++) {if (i != pageNum) {continue;}// 获取当前Page页面PDPage page = doc.getPage(i);// 获取对应页面的资源对象PDResources resources = page.getResources();// 遍历当前页面所有内容,找出图片对象for (COSName cosName : resources.getXObjectNames()) {PDXObject pdxObject = resources.getXObject(cosName);// 判断是不是图片对象if (pdxObject instanceof PDImageXObject) {// 获取图片对象BufferedImage image = ((PDImageXObject) pdxObject).getImage();// 保存到本地磁盘里面ImageIO.write(image, "JPEG", new File(imagePath));}}}doc.close(); // 关闭PDF文档} catch (Exception e) {e.printStackTrace();}return imagePath;}public static void main(String[] args) {String imgPath = "E:\\img\\002.jpg";String destPdf = "E:\\demo\\img.pdf";readerImageFromPdf(destPdf, imgPath, 0);}
}

(2)运行效果

到此,PDFBox操作图片就介绍完啦。

综上,这篇文章结束了,主要介绍PDFBox操作PDF文档之添加本地图片、添加网络图片、图片宽高自适应、图片水平垂直居中对齐。

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

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

相关文章

学校招生报名小程序开发笔记(一)

背景 这是一个以报名为核心的职业学校招生小程序&#xff0c;目的是方便想要系统学习技能&#xff0c;入门某项技能或者领域的初高中毕业生&#xff0c;了解该学校的基本情况及各个专业&#xff0c;并提供报名路径&#xff0c;致力于技能型人才培养 功能规划 主要功能包括专…

IntelliJ IDEA下载安装教程

目录 友情提醒第一章、IDEA软件下载1.1&#xff09;官网下载 第二章、IDEA软件安装2.1&#xff09;以"ideaIU-2018.3.3.exe"为例3.2&#xff09;启动IDEA软件 友情提醒 点击文章目录可以跳转 第一章、IDEA软件下载 IDEA 全称 IntelliJ IDEA。在智能代码助手、代码…

互联网医院牌照|互联网医院牌照办理|互联网医院申办

互联网医院牌照是一种医疗机构执业许可证&#xff0c;在行业中也称为“互联网医疗许可证”。互联网医院牌照由卫生健康委员会颁发&#xff0c;一般分为两种&#xff1a;一种是互联网医疗信息服务资质&#xff0c;另一种是互联网诊疗资质。那么如何申办互联网医院牌照呢&#xf…

面试之双亲委派原理

一面腾讯提问:如果我自定义一个 new Object 类&#xff0c;请问这个类是否会被加载&#xff1f; 回答&#xff1a;不会&#xff0c;因为双亲委派&#xff0c;向上加载。回答的过程中磨磨唧唧。当然最后一面也是没有过。 总之一句话&#xff1a;向上加载&#xff0c;向下委派. …

Morris遍历--验证二叉搜索树(java)

Morris遍历- 验证二叉搜索树题目描述Morris 遍历解题代码演示&#xff1a; morris 遍历改写后序遍历 验证二叉搜索树 来源&#xff1a;力扣&#xff08;LeetCode&#xff09; 链接&#xff1a;https://leetcode.cn/problems/validate-binary-search-tree 题目描述 给你一个二叉…

Mybatis中表关系查询结果集映射

文章目录 前言1. 实体类设计1.1 用户表1.2 地址表1.3 博客表1.4 粉丝互关表 2.插入数据3.表关联查询3.1 一对一关系3.2 一对多关系3.3 多对多关系 前言 resultMap 元素是 MyBatis 中最重要最强大的元素。它可以让你从 90% 的 JDBC ResultSets 数据提取代码中解放出来&#xff…

IMU+激光雷达实现大规模动作捕捉

VR技术的兴起&#xff0c;使得动作捕捉这门让人们可以使用肢体语言在虚拟世界中进行互动和交流的技术逐渐成为热门。随着科技的进步&#xff0c;如今的动作捕捉技术已经十分成熟&#xff0c;但在大规模场景中准确地捕捉人体运动仍然具有挑战性。它对于体育大型赛事、舞台表演、…

WPF Prims框架详解

文章目录 前言Prism基本使用Prism选择&#xff0c;DryIoc还是UnityPrism基本框架搭建Prism动态更新View和ViewModel对应关系参数动态更新函数动态绑定 prism新建项目模板region使用事例测试是否限制空间 消息订阅如何使用消息订阅使用建议 路由导航对话框/弹窗功能实现代码 前言…

C#开发的OpenRA游戏之维修按钮

C#开发的OpenRA游戏之维修按钮 前面分析物品的变卖按钮,如果理解这个流程,再看其它按钮的流程,其实是一样的,所以前面的文章是关键,只有理解通透的基础之上,才能继续往下。 维修按钮的存在价值,就是当建筑物受到敌方破坏,还没有完全倒掉之前,可以使用金币来进行修理。…

Redis学习(四)Redis原理:底层数据结构、网络模型、内存回收策略

文章目录 Redis底层数据结构SDS 动态字符串IntSet 整数集合Dict 字典Dict伸缩中的渐进式再哈希 ZipList 压缩列表QuickLisk 快速列表SkipList 跳表动态索引建立 RedisObject变量类型与数据结构实现StringListSetZSetHash Redis网络模型Redis是单线程还是多线程&#xff1f;为什…

用vscode远程连接Linux服务器后,如何创建自己的账号

1. 打开终端&#xff08;Terminal&#xff09;窗口 2. 在终端中创建新的用户账号 &#xff08;假设您要创建的用户名为 “newuser”&#xff09;&#xff0c;在命令执行期间&#xff0c;需要提供新用户的密码。按照提示进行操作。 先输入登录的管理员账号密码。 再输入创建的…

CMS系统访问权限限制

创建一些全局的通用方法 const USER_KEY "USER_KEY" const TOKEN_KEY "JWT_TOKEN_KEY"class Auth {constructor() {this.token nullthis.user nullthis.token localStorage.getItem(TOKEN_KEY)const userJson localStorage.getItem(USER_KEY)if (use…