【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页面内容流里面,案例代码如下:

java 复制代码
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)案例代码

java 复制代码
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)图片缩放代码

java 复制代码
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个pt
            yAxis = (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)案例代码

java 复制代码
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文档之添加本地图片、添加网络图片、图片宽高自适应、图片水平垂直居中对齐。

相关推荐
ydjs678899-bot24 分钟前
如何在Java中打印pdf静默打印和打印对话框选择
java·python·pdf
SamChan902 小时前
PDF 翻译后 1,250 变成 1.250,是错了吗?用 Python 核对数字格式
python·pdf·ocr·数据校验·文档翻译
开开心心就好5 小时前
打印机卡住打不了?一键清理卡死打印队列
服务器·开发语言·算法·pdf·ocr·idea·visual studio code
打工仔折腾 AI1 天前
在线PDF工具隐私焦虑?把BentoPDF部署到极空间NAS本地处理
人工智能·后端·python·pdf·ai agent 实战
霸道流氓气质1 天前
AI 简历制作平台:结构化输出解析、多模板渲染与 PDF 导出的 Vue3 + Spring AI 全栈实战
人工智能·spring·pdf
开开心心_Every1 天前
黄金价格软件国内外价格实时监控超方便
运维·服务器·游戏·智能手机·pdf·lua·perl
JasonSJX1 天前
DRM-X 5.0 PDF 保护更新:Windows 与 Mac 打印保留用户水印,ZJGet iOS 版支持 PDF 阅读
macos·pdf
shmily麻瓜小菜鸡2 天前
前端实现图片与PDF文字识别敏感信息打码方案
前端·pdf·状态模式
ComPDFKit2 天前
PDF 涂黑后还能复制?用 ComPDF 检查敏感文字是否真正删除
pdf
飞塔老梅子2 天前
21. 按页数或章节分割大PDF文件 ❀ 老梅子学AI
pdf·分割·basic·pdfsam·裁切