使用PDFBox封装一个简单易用的工具类快速生成pdf文件

news2024/11/25 22:58:02

文章目录

    • 一、PDFbox说明
      • 1、坐标
      • 2、线
      • 3、图
      • 4、字
      • 5、字体加载
      • 6、jfreechart图表转字节数组
      • 7、依赖
    • 二、PDFbox样式
      • 1、文字颜色
      • 2、线颜色
      • 3、线样式
    • 三、工具类
      • 边框样式
      • 对齐样式
      • 图片列
      • pdf工具类
      • 测试方法
    • 四、效果图

一、PDFbox说明

1、坐标

文档左下角为坐标原点,x轴向右从0增加,y轴向上增加

2、线

以起始位置至终点一条线,线宽以垂直于起始至终止连线方向发散,例如线宽20,起始位置(0,10),终止位置(500,10)则线实际所占位置为(0,0),(0,20),(500,0),(500,20)所围成的长方形区域

3、图

图位置以左下角为原点向右上方发散

4、字

字的位置以左下角为原点向右上方发散

        // 横线
        contentStream.moveTo(0, 10);
        contentStream.lineTo(540, 10);
        contentStream.stroke();
 
        // 竖线
        contentStream.moveTo(10, 0);
        contentStream.lineTo(10, 540);
        contentStream.stroke();
 
        // 斜线
        contentStream.moveTo(0, 0);
        contentStream.lineTo(540, 540);
        contentStream.stroke();
 
        // 图片
        final byte[] imageByte = IOUtils.toByteArray(Objects.requireNonNull(DrawTableUtils.class.getClassLoader().getResourceAsStream("yellow.png")));
        final PDImageXObject image = PDImageXObject.createFromByteArray(document, imageByte, "yellow.png");
        contentStream.drawImage(image, 20, 0, 50, 50);
        // 文字
        contentStream.beginText();
        contentStream.setFont(PDType1Font.HELVETICA_BOLD, 10);
        contentStream.newLineAtOffset(0, 10);
        String text = "This is the sample document and we are adding content to it.";
        contentStream.showText(text);
        contentStream.endText();

5、字体加载

1、ttf类型字体加载

       InputStream inFont = DrawTableUtils.class.getClassLoader().getResourceAsStream(fontName);
        PDType0Font normalFont = PDType0Font.load(document, inFont);
        PDType0Font boldFont = null;

2.otf类型字体加载

        InputStream normalStream = DrawTableUtils.class.getClassLoader().getResourceAsStream(fontName);
        assert normalStream != null;
        OpenTypeFont normalOtfFont = new OTFParser(false, true).parse(normalStream);
        PDType0Font normalFont = PDType0Font.load(document, normalOtfFont, false);

6、jfreechart图表转字节数组

JFreeChart chart = new JFreeChart(title, xyplot);
// 图例字体清晰
chart.setTextAntiAlias(true);
chart.setBackgroundPaint(Color.WHITE);
TextTitle textTitle = chart.getTitle();
textTitle.setFont(new Font("黑体", Font.PLAIN, 20));
BufferedImage bufferedImage = chart.createBufferedImage(600, 300);
byte[] bytes = ChartUtilities.encodeAsPNG(bufferedImage);

7、依赖

		<dependency>
			<groupId>org.apache.pdfbox</groupId>
			<artifactId>pdfbox</artifactId>
			<version>2.0.28</version>
		</dependency>

二、PDFbox样式

1、文字颜色

Color color = new Color(255,0,0);
contentStream.setNonStrokingColor(color);

2、线颜色

Color color = new Color(255, 0, 0);
contentStream.setStrokingColor(color);

3、线样式

 float[] a={
   3,5};
        contentStream.setLineDashPattern(a, 0);
        contentStream.moveTo(0, 20);
        contentStream.lineTo(540, 20);
        contentStream.stroke();
 
        contentStream.setLineDashPattern(a, 20);
        contentStream.moveTo(0, 50);
        contentStream.lineTo(540, 50);
        contentStream.stroke();
 
        float[] b={
   3};
        contentStream.setLineDashPattern(b, 20);
        contentStream.moveTo(0, 80);
        contentStream.lineTo(540, 80);
        contentStream.stroke();

contentStream.setLineDashPattern(a, 0);

第一个参数 a={3,5} 3表明虚线宽度为3,5表明虚线间隔为5 。当a={3}时表明虚线宽度为3,间隔为3

第二个参数0表明虚线偏移量

三、工具类

边框样式

public enum BorderStyle {
   
 
    SOLID(new float[]{
   }, 0),
    DOTTED(new float[]{
   1}, 1),
    DASHED(new float[]{
   5,2}, 1);
 
    private final float[] pattern;
    private final int phase;
 
    BorderStyle(float[] pattern, int phase) {
   
        this.pattern = pattern;
        this.phase = phase;
    }
 
    public float[] getPattern() {
   
        return pattern;
    }
 
    public int getPhase() {
   
        return phase;
    }
}

对齐样式

public enum HorizontalAlignment {
   
 
    LEFT, CENTER, RIGHT
 
}

 
@Data
public class PdfTable {
   
    /**
     * 行
     */
    private List<PdfRow> rows;
    /**
     * 字体
     */
    private String font;
    public void addRow(PdfRow row){
   
        rows.add(row);
    }
}

@Data
@Builder
public class PdfRow {
   
    /**
     * 列
     */
    private List<PdfColumn> pdfColumns;
    /**
     * 行高
     */
    private float height;
    /**
     * 边框样式,仅下边框生效
     */
    private BorderStyle borderStyle;
    /**
     * 边框颜色
     */
    @Builder.Default
    private Color boderColor=Color.BLACK;
    /**
     * 下边框是否生效
     */
    private boolean downBorder;
 
    public void addColumn(PdfColumn pdfColumn){
   
        pdfColumns.add(pdfColumn);
    }
}

@Data
@Builder
public class PdfColumn {
   
    /**
     * 背景颜色
     */
    @Builder.Default
    private Color backGround = Color.WHITE;
    /**
     * 边框颜色
     */
    @Builder.Default
    private Color borderColor = Color.BLACK;
    /**
     * 文字颜色
     */
    @Builder.Default
    private Color textColor= Color.BLACK;
    /**
     * 加粗
     */
    @Builder.Default
    private boolean block=false;
    /**
     * 文字大小
     */
    @Builder.Default
    private float fontSize=10F;
    /**
     * 偏移
     */
    @Builder.Default
    private float offset=0F;
    /**
     * 文字位置
     */
    @Builder.Default
    private HorizontalAlignment align =HorizontalAlignment.CENTER;
    /**
     * 自动宽度
     */
    @Builder.Default
    private boolean autoWidth=false;
    /**
    * 自动换行
    */
    @Builder.Default
    private boolean autoWidth=false;
    /**
     * 左边框
     */
    private boolean leftBorder;
    /**
     * 右边框
     */
    private boolean rightBorder;
    /**
     * 名称
     */
    private String name;
    /**
     * 宽度,仅在自动宽度未生效时启用
     */
    private float width;
    /**
     * 图片,图片生效时其他属性均不生效
     */
    private PdfColumnImage columnImage;
}

图片列

@Data
@Builder
public class PdfColumnImage {
   
    /**
     * 图片名称/路径
     */
    private String image;
    /**
     * x轴位置
     */
    private float x;
    /**
     * y轴位置
     */
    private float y;
    /**
     * 图片宽度
     */
    private float width;
    /**
     * 图片高度
     */
    private float height;
}

pdf工具类

public class DrawTableUtils {
   
 
    /**
     * 页边距
     */
    private static final float PADDING = 30;
    /**
     * 下表格线偏移
     */
    private static final float DOWN_LINE_PADDING = 0.5f;
    /**
     * 边框宽度
     */
    private static final float BORDER_WIDTH = 1;
    /**
     * 生成PDF
     *
     * @param table pdf数据
     * @throws IOException
     */
    public static void createDocument(PdfTable table) throws IOException {
   
        // 初始化文档
        PDDocument document = new PDDocument();
        final PDPage page = new PDPage(PDRectangle.A4);
        document.addPage(page);
        // 字体
        String fontName = table.getFont();
        InputStream inFont = org.bmc.DrawTableUtils.class.getClassLoader().getResourceAsStream(fontName);
        PDType0Font font = PDType0Font.load(document, inFont);
        // 页
        int pageNum = 1;
        // 初始化文档位置
        org.bmc.DrawTableUtils.Position position = new org.bmc.DrawTableUtils.Position(PADDING, page.getMediaBox().getHeight() - PADDING, 0);
        PDPageContentStream contentStream = new PDPageContentStream(document, page);
 
        for (PdfRow row : table.getRows()) {
   
            // 分页
            if (position.startY <= PADDING * 2) {
   
                pageNum++;
                PDPage pdPage = new PDPage(PDRectangle.A4);
                document.addPage(pdPage);
                position.startY = page.getMediaBox().getHeight() - PADDING;
                contentStream.close();
                contentStream = new PDPageContentStream(document, pdPage);
            }
 
            drawLine(row, document, contentStream, position, font);
 
            if (row.isDownBorder()) {
   
                drawDrownBorder(contentStream, page, row, position);
            }
 
 
        }
        contentStream.close();
        // 页脚
        drawPageFoot(document, pageNum, font);
        // 保存文档
        document.save("D:/mypdf.pdf");
        document.close();
    }
 
 
    /**
     * 生成表格下框,以行为单位
     *
     * @param contentStream 流
     * @param page          页
     * @param row           行
     * @param position      位置
     * @throws IOException
     */
    private static void drawDrownBorder(PDPageContentStream contentStream, PDPage page, PdfRow row, org.bmc.DrawTableUtils.Position position) throws IOException {
   
        contentStream.

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

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

相关文章

Cluade3干货:超越GPT,模型特点分析+使用教程|2024年3月更新

就在刚刚&#xff0c;Claude 发布了最新的大模型 Claude3&#xff0c;并且一次性发布了三个模型&#xff0c;分别是 Claude 3 Haiku&#xff1a;&#xff08;日本俳句 &#xff09;Claude 3 Sonnet&#xff08;英文十四行诗&#xff09;Claude 3 Opus&#xff08;古典乐作品集…

HarmonyOS NEXT应用开发案例——滑动页面信息隐藏与组件位移效果

介绍 在很多应用中&#xff0c;向上滑动"我的"页面&#xff0c;页面顶部会有如下变化效果&#xff1a;一部分信息逐渐隐藏&#xff0c;另一部分信息逐渐显示&#xff0c;同时一些组件会进行缩放或者位置移动。向下滑动时则相反。 效果图预览 使用说明 向上滑动页面…

Vue:双token无感刷新

文章目录 初次授权与发放Token&#xff1a;Access Token的作用&#xff1a;Refresh Token的作用&#xff1a;无感刷新&#xff1a;安全机制&#xff1a;后端创建nest项目AppController 添加login、refresh、getinfo接口创建user.dto.tsAppController添加模拟数据 前端Hbuilder创…

ARM中专用指令(异常向量表、异常源、异常返回等)

状态寄存器传送指令 CPSR寄存器 状态寄存器传送指令:访问&#xff08;读写&#xff09;CPSR寄存器 读CPSR MRS R1, CPSR R1 CPSR 写CPSR MSR CPSR, #0x10 0x10为User模式&#xff0c;且开启IRQ和FRQ CPSR 0x10 在USER模式下不能随意修改CPSR&#xff0c;因为USER模式…

js五星评价的制作方法

方法有两种&#xff0c;1、jquer插件&#xff1b;2、图片循环&#xff1b; 第一种、效果图 代码 <!DOCTYPE html> <html lang"zh"> <head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"…

机器学习---拉格朗日乘子法、Huber Loss、极大似然函数取对数的原因

1. 拉格朗日乘子法 拉格朗日乘子法&#xff08;Lagrange multipliers&#xff09;是一种寻找多元函数在一组约束下的极值的方法。通过引 入拉格朗日乘子&#xff0c;可将有d个变量与k个约束条件的最优化问题转化为具有d&#xff0b;k个变量的无约束优化 问题求解。本文希望通…

java工程师面试笔试题,阿里+头条+抖音+百度+蚂蚁+京东面经

前言 分布式事务主要解决分布式一致性的问题。说到底就是数据的分布式操作导致仅依靠本地事务无法保证原子性。与单机版的事务不同的是&#xff0c;单机是把多个命令打包成一个统一处理&#xff0c;分布式事务是将多个机器上执行的命令打包成一个命令统一处理。 MySQL 提供了…

软件测试计划包括哪些内容?专业第三方软件测试机构推荐

软件测试计划是为确保软件质量而制定的详细计划&#xff0c;它在软件开发周期中扮演着至关重要的角色。一个良好的软件测试计划可以确保软件在交付给最终用户之前经过全面的测试和验证&#xff0c;减少软件出现缺陷和问题的可能性。 软件测试计划一般包括以下内容&#xff1a;…

汇编程序中引用头文件

文章目录 写在前面x86汇编示例(AT&T风格ARM汇编示例运行结果 写在前面 汇编程序中也是可以使用头文件的&#xff0c;因为头文件实际上就是预处理中的一环&#xff0c;使用预处理器也对汇编程序中的头文件进行预处理 本文使用的汇编例程&#xff1a; x86版 AT&T汇编hel…

打印螺旋矩阵

打印螺旋矩阵 题目 如&#xff1a;输入 n 5&#xff1b; 输出&#xff1a; 1 2 3 4 5 16 17 18 19 6 15 24 25 20 7 14 23 22 21 8 13 12 11 10 9解题 这种规律打印题我个人感觉是真的不好写&#xff0c;一看答案感觉也就那回事&#xff0c;真自己琢磨&#xff0c;半…

15 实战:Kaggle房价预测 + 课程竞赛:加州2020年房价预测【李沐动手学深度学习课程笔记】

15 实战&#xff1a;Kaggle房价预测 课程竞赛&#xff1a;加州2020年房价预测【李沐动手学深度学习课程笔记】https://zhuanlan.zhihu.com/p/685343754 写在前面&#xff1a;这里格式很乱&#xff0c;代码直接去知乎copy 1 实战Kaggle比赛&#xff1a;预测房价 1.1 实现几个函…

flowable使用taskService.addComment新增评论需要full_msg字段进行读取

背景 在构建创业项目JeecgFlow过程中&#xff0c;在调用taskService.addComment接口出现了异常。就是数据存储的Message信息出现了截取&#xff0c;也就是存储不完整。 效果如下. flowable版本6.7.2 问题排查 接口详解及问题代码 //新增评论的接口说明 Comment addComment(…

华为OD机试“HJ5 进制转换”Java编程解答

描述 写出一个程序&#xff0c;接受一个十六进制的数&#xff0c;输出该数值的十进制表示。 数据范围&#xff1a;保证结果在 1≤n≤231−1 输入描述&#xff1a; 输入一个十六进制的数值字符串。 输出描述&#xff1a; 输出该数值的十进制字符串。不同组的测试用例用\…

OpenAI高管联名回击:马斯克曾提议并入特斯拉,认为OpenAI注定失败

丨划重点 ① OpenAI周二发文回应马斯克提起的诉讼&#xff0c;称对双方走到这一步感到很难过。 ② 这篇博文的作者包括了OpenAI五位高管&#xff0c;其中首席科学家苏茨凯弗已经久违露面。 ③ OpenAI证实&#xff0c;只从马斯克处获得不到4500万美元资金&#xff0c;其他支持者…

企业对接Walmart平台API流程 On-request Reports API(二)

对接On-request Reports API 1、对接指南1.1 报告生成时间1.2 报告保留期1.3 请求限制1.4 报告请求工作流如何申请报告第 1 步&#xff1a;申请取消报告第 2 步&#xff1a;获取报表可用性状态第 3 步&#xff1a;下载报告 URL 2、代码实现2.1、获取访问API的token2.2、构建公共…

【记录】IDA|IDA设置text view为默认,并解决IDA7.6打开新固件卡顿的问题

版本&#xff1a;IDA Pro 7.6 Graph View&#xff08;控制流视图&#xff09;其实我真的看得很少&#xff0c;因为遇到分析难题时总是是因为间接调用&#xff0c;它根本分析不出来。但是一开IDA它就自动分析这个特别卡。所以今天想彻底解决一下&#xff0c;让默认打开为Text V…

day7-网络编程

1>基于UDP的网络聊天室 Ser.c #include <myhead.h> #define SER_IP "10.211.55.9" // 服务器IP #define SER_PORT 9999struct user {char usrName[20];struct sockaddr_in cin; }; int main(int argc, char const *argv[]) {// 1.创建用于监听的套接字int…

2024-3-6-数据库作业

作业&#xff1a;数据库操作的增、删、改完成 &#xff08;目前只能实现静态管理&#xff09; 源代码&#xff1a; #include <myhead.h> void do_add(sqlite3 *ppDb) {char *errmsg NULL;char sql[128] "insert into Worker values(1001,小张,15000);";//…

《中学综合素质》黄金卷(二)

2.对下图漫画描述不正确的是&#xff08;A &#xff09;。 A.忽视了平等待生 B.忽视了学生的个性发展 C.忽视了学生的差异性 D.违背了素质教育观 8.“任何组织或者个人不得隐匿、毁弃、非法删除未成年人的信件、日记、电子邮件或者其 他网络通讯内容”&#xff0c;对照《中华…

离散数学例题——3.计数和集合论(集合与二元关系)

幂集与子集数目 集合运算 集合的证明 集合构建符号证明 用集合成员表证明 用集合运算定律证明 无限集、等势、无限可数集和无限不可数集的基数 关系的定义、个数 关系的表示 关系的运算 使用矩阵运算实现关系的运算 关系的证明 关系的性质 自反性和反自反性&#xff08;矩阵对…