pdfbox工具类2.0

一、优化

此次修改优化了pdf工具类已有功能,同时可以用更简单的方式实现更复杂的样式,整体使用方式与前版并无明显区别

1、手动换页,表格换页

可以指定何时进行换页操作,同一表格在一个页显示,nextPage为强制换页,autoPage为表格换页

Float height = null;
if(pdfTable.isAutoPage())
{
    height = pdfTable.getRows().stream().map(PdfRow::getHeight).reduce(Float::sum).get();
}
// 强制换页
if(pdfTable.isNextPage() || (pdfTable.isAutoPage() && position.startY - height <= VERTICAL_PADDING))
{
    pageNum++;
    page = new PDPage(new PDRectangle(pdfTable.getWidth(), pdfTable.getHeight()));
    document.addPage(page);
    position.startY = page.getMediaBox().getHeight() - VERTICAL_PADDING;
    contentStream.close();
    contentStream = new PDPageContentStream(document, page);
}

2、支持画线(一阶贝赛尔曲线)

private static void drawLineBorder(PDPageContentStream contentStream, PdfColumn column, Position position) throws IOException
{
    PdfColumnLine columnLine = column.getColumnLine();
    // 控制点为空置为起点
    if(columnLine.getX2() == null)
    {
        columnLine.setX2(columnLine.getX1());
        columnLine.setY2(columnLine.getY1());
    }
    contentStream.setLineWidth(columnLine.getWidth());
    contentStream.setLineCapStyle(columnLine.getLineCapStyle().getStyle());
    contentStream.setLineDashPattern(columnLine.getBorderStyle().getPattern(), columnLine.getBorderStyle().getPhase());
    contentStream.setStrokingColor(columnLine.getColor());
    // 起点
    contentStream.moveTo(position.startX + columnLine.getX1(), position.startY + columnLine.getY1());
    // 贝赛尔曲线
    contentStream.curveTo(position.startX + columnLine.getX1(), position.startY + columnLine.getY1(), position.startX + columnLine.getX2(), position.startY + columnLine.getY2(), position.startX + columnLine.getX3(), position.startY + columnLine.getY3());
    contentStream.stroke();
}

3、画线方法(进度条)

 /**
  * 进度条
  * @param x 相对位置x
  * @param y 相对位置y
  * @param percent 进度条百分比
  * @param width 进度条长度
  * @param lineWidth 进度条宽度
  * @param borderStyle 线样式
  * @param capStyle 端点样式
  * @return
  */
 public static ArrayList addProgress(float x, float y, float percent, float width, float lineWidth, BorderStyle borderStyle, LineCapStyle capStyle)
 {
     ArrayList columns = new ArrayList < > ();
     // 背景灰
     PdfColumn build = PdfColumn.builder().columnLine(PdfColumnLine.builder().x1(x).y1(y).x3(x + width).y3(y).width(lineWidth).color(new Color(245, 245, 245)).borderStyle(borderStyle).lineCapStyle(capStyle).build()).build();
     columns.add(build);
     // 前景绿
     build = PdfColumn.builder().columnLine(PdfColumnLine.builder().x1(x).y1(y).x3(x + width * percent / 100).y3(y).width(lineWidth).color(new Color(97, 183, 179)).borderStyle(borderStyle).lineCapStyle(capStyle).build()).build();
     columns.add(build);
     return columns;
 }

4、圆角矩形

 /**
  * 圆角矩形
  * @param x 相对位置x(左下角)
  * @param y 相对位置y(左下角)
  * @param width 矩形宽度
  * @param height 矩形高度
  * @param radio 圆角半径
  * @param color 颜色
  * @param borderStyle 线样式
  * @return
  */
 public static PdfRow addRect(float x, float y, float width, float height, float radio, Color color, BorderStyle borderStyle)
 {
     // 逆时针方向作图
     PdfRow row = PdfRow.builder().height(0).columns(new ArrayList < > ()).build();
     // 左下圆角
     row.addColumn(PdfColumn.builder().columnLine(PdfColumnLine.builder().x1(x).y1(y + radio).x2(x).y2(y).x3(x + radio).y3(y).color(color).borderStyle(borderStyle).build()).build());
     // 下部横线
     row.addColumn(PdfColumn.builder().columnLine(PdfColumnLine.builder().x1(x + radio).y1(y).x3(x + width - radio).y3(y).color(color).borderStyle(borderStyle).build()).build());
     // 右下圆角
     row.addColumn(PdfColumn.builder().columnLine(PdfColumnLine.builder().x1(x + width - radio).y1(y).x2(x + width).y2(y).x3(x + width).y3(y + radio).color(color).borderStyle(borderStyle).build()).build());
     // 右侧竖线
     row.addColumn(PdfColumn.builder().columnLine(PdfColumnLine.builder().x1(x + width).y1(y + radio).x3(x + width).y3(y + height - radio).color(color).borderStyle(borderStyle).build()).build());
     // 右上圆角
     row.addColumn(PdfColumn.builder().columnLine(PdfColumnLine.builder().x1(x + width).y1(y + height - radio).x2(x + width).y2(y + height).x3(x + width - radio).y3(y + height).color(color).borderStyle(borderStyle).build()).build());
     // 上部直线
     row.addColumn(PdfColumn.builder().columnLine(PdfColumnLine.builder().x1(x + width - radio).y1(y + height).x3(x + radio).y3(y + height).color(color).borderStyle(borderStyle).build()).build());
     // 左上圆角
     row.addColumn(PdfColumn.builder().columnLine(PdfColumnLine.builder().x1(x + radio).y1(y + height).x2(x).y2(y + height).x3(x).y3(y + height - radio).color(color).borderStyle(borderStyle).build()).build());
     // 左部直线
     row.addColumn(PdfColumn.builder().columnLine(PdfColumnLine.builder().x1(x).y1(y + height - radio).x3(x).y3(y + radio).color(color).borderStyle(borderStyle).build()).build());
     return row;
 }

5、自动行高

自适应行高度,可按空格或长度换行计算行高

/**
 * 计算行高,以空格切分数据
 *
 * @param row 行
 * @param normalFont 字体
 * @return float 当前行高度
 */
@SneakyThrows
private static float getHeight(PdfRow row, PDType0Font normalFont, PDType0Font boldFont)
{
    float height = row.getHeight();
    int size = 0;
    if(row.isAutoHeight())
    {
        for(PdfColumn column: row.getColumns())
        {
            if(column.isAutoLine())
            {
                float titleHeight = normalFont.getFontDescriptor().getCapHeight() / 1000 * column.getFontSize();
                if(column.getNameList() != null)
                {
                    size = 0;
                    boolean[] nameFlag = new boolean[column.getNameList().length];
                    for(int i = 0; i < column.getNameList().length; i++)
                    {
                        String name = column.getNameList()[i];
                        // 计算当前name所需行数
                        size += getNameLineSize(normalFont, boldFont, column, name, nameFlag, i);
                    }
                }
                else if(StringUtils.isNotEmpty(column.getName()))
                {
                    boolean[] nameFlag = new boolean[1];
                    size = getNameLineSize(normalFont, boldFont, column, column.getName(), nameFlag, 0);
                }
                height = Math.max(height, (titleHeight * 2.2 f) * size);
            }
        }
    }
    return height;
}

 6、单元格合并

nameList保存需要多行显示的文字

 /**
  * 写入分行数据
  *
  * @param row 当前行信息
  * @param contentStream 流
  * @param position 位置
  * @param normalFont 正常字体
  * @param column 列
  * @param totalLine 分行后总行数
  * @param splitName 分行后每行内容
  * @param maxCeil 最大行数
  * @throws IOException
  */
 private static void drawSplitLine(PdfRow row, PDPageContentStream contentStream, Position position, PDType0Font normalFont, PDType0Font boldFont, PdfColumn column, int totalLine, String[] splitName, int maxCeil) throws IOException
     {
         int currentCel = totalLine;
         // 分行后单行行高
         float hi = row.getHeight() / totalLine;
         for(String cellName: splitName)
         {
             // 写入分行数据
             Position aPosition = new Position(position.startX, position.startY + hi * (--currentCel), position.getTitleHeight());
             PdfColumn aColumn = PdfColumn.builder().horizontalAlignment(column.getHorizontalAlignment()).fontSize(column.isAutoSize() ? column.getFontSize() / maxCeil * 1.8 f : column.getFontSize()).name(cellName).width(column.getWidth()).offset(column.getOffset()).block(column.isBlock()).build();
             // float pWidth = normalFont.getStringWidth(aColumn.getName() == null ? \"\" : aColumn.getName()) / 1000 * aColumn.getFontSize();
             float pWidth = getStringWidth(normalFont, boldFont, aColumn.getName() == null ? \"\" : aColumn.getName(), aColumn);
                 drawMuLine(contentStream, aPosition, aColumn, pWidth, hi, normalFont, boldFont);
                 if(currentCel == 0)
                 {
                     break;
                 }
             }
         }

7、同行字体不同文字颜色自定义

/**
 *
 * @param contentStream
 * @param position
 * @param column
 * @param titleWidth
 * @param rowHeight
 * @param normalFont
 * @param boldFont
 * @throws IOException
 */
private static void drawTextLine(PDPageContentStream contentStream, Position position, PdfColumn column, float titleWidth, float rowHeight, PDType0Font normalFont, PDType0Font boldFont) throws IOException
{
    // 文字
    contentStream.beginText();
    contentStream.setFont(normalFont, column.getFontSize());
    contentStream.setNonStrokingColor(column.getTextColor());
    // 加粗,使用粗体文字
    if(column.isBlock())
    {
        contentStream.setFont(boldFont, column.getFontSize());
    }
    HorizontalAlignment horizontalAlignment = column.getHorizontalAlignment();
    VerticalAlignment verticalAlignment = column.getVerticalAlignment();
    float x = 0, y = 0;
    if(horizontalAlignment == HorizontalAlignment.CENTER)
    {
        // 居中
        x = (column.getWidth() - titleWidth) / 2 + position.startX + column.getOffset();
    }
    else if(horizontalAlignment == HorizontalAlignment.LEFT)
    {
        // 居左
        x = position.startX + column.getOffset();
    }
    else if(horizontalAlignment == HorizontalAlignment.RIGHT)
    {
        // 居右
        x = position.startX + column.getOffset() + column.getWidth() - titleWidth;
    }
    if(verticalAlignment == VerticalAlignment.BOTTOM)
    {
        // 底部
        y = position.startY + position.titleHeight / 2;
    }
    else if(verticalAlignment == VerticalAlignment.CENTER)
    {
        // 居中
        y = position.startY + rowHeight / 2 - position.titleHeight / 2;
    }
    contentStream.newLineAtOffset(x, y);
    if(column.getNameList() != null)
    {
        String[] nameList = column.getNameList();
        for(int i = 0; i < nameList.length; i++)
        {
            String name = nameList[i];
            if(column.getTextColorList() != null)
            {
                contentStream.setNonStrokingColor(column.getTextColorList()[i]);
            }
            contentStream.showText(name);
        }
    }
    else
    {
        contentStream.showText(column.getName() == null ? "" : column.getName());
    }
    contentStream.endText();
    
}

8、超长自动截断

// 自动截断
if(titleWidth > column.getWidth())
{
    float length = 0;
    int i = 0;
    float latestLength = 0;
    StringBuilder builder = new StringBuilder();
    float sWidth = 0;
    if(column.getNameList() != null)
    {
        // 计算长度超长位置
        String[] nameList = column.getNameList();
        for(; i < nameList.length; i++)
        {
            String name = nameList[i];
            latestLength = getStringWidth(normalFont, boldFont, name, column);
            length += latestLength;
            if(length >= column.getWidth())
            {
                break;
            }
        }
        // 计算超长位置字符
        String name = nameList[i];
        for(int j = 0; j < name.length(); j++)
        {
            String s = name.substring(j, j + 1);
            sWidth += getStringWidth(normalFont, boldFont, s, column);
            if(sWidth >= column.getWidth() - length + latestLength)
            {
                titleWidth = sWidth - getStringWidth(normalFont, boldFont, s, column);
                break;
            }
            else
            {
                builder.append(s);
            }
        }
        nameList[i] = builder.toString();
        // 重置后续部分内容
        for(++i; i < nameList.length; i++)
        {
            nameList[i] = \"\";
        }
    }
    else
    {
        // 计算超长位置字符
        String name = column.getName();
        for(int j = 0; j < name.length(); j++)
        {
            String s = name.substring(j, j + 1);
            sWidth += getStringWidth(normalFont, boldFont, s, column);
            if(sWidth >= column.getWidth())
            {
                titleWidth = sWidth - getStringWidth(normalFont, boldFont, s, column);
                break;
            }
            else
            {
                builder.append(s);
            }
        }
        column.setName(builder.toString());
    }
}

 

二、工具类

边框样式

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 rows;
    /**
     * 字体
     */
    private String font;
    /**
     * 语言
     */
    private String language;
    /**
     * 页眉
     */
    private PdfRow pageHead;
    /**
     * 分页后表头
     */
    private List titleRows;
    /**
     * 分页标志
     */
    private boolean nextPage = false;
    /**
     * 自动分页
     */
    private boolean autoPage = false;
    /**
     * 表单
     */
    private List tableList;
    /**
     * 文档宽度(默认A4)
     */
    private float width = 595.27563 F;
    /**
     * 文档高度(默认A4)
     */
    private float height = 841.8898 F;
    public void addRow(PdfRow row)
    {
        rows.add(row);
    }
    public void addTitleRow(PdfRow row)
    {
        titleRows.add(row);
    }
}

  行

@Data
@Builder
public class PdfRow
{
    /**
     * 列
     */
    private List columns;
    /**
     * 行高
     */
    private float height;
    /**
     * 自动行高
     */
    @
    Builder.Default
    private boolean autoHeight = false;
    /**
     * 边框样式
     */
    @
    Builder.Default
    private BorderStyle borderStyle = BorderStyle.SOLID;
    /**
     * 边框颜色
     */
    @
    Builder.Default
    private Color boderColor = Color.BLACK;
    /**
     * 下边框是否生效
     */
    private boolean downBorder;
    /**
     * 上边框是否生效
     */
    private boolean upBorder;
    public void addColumn(PdfColumn pdfColumn)
    {
        columns.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;
    /**
     * 文字颜色,
     */
    private Color[] textColorList;
    /**
     * 加粗
     */
    @Builder.Default
    private boolean block = false;
    /**
     * 文字大小
     */
    @Builder.Default
    private float fontSize = 10 F;
    /**
     * 偏移
     */
    @Builder.Default
    private float offset = 0 F;
    /**
     * 文字位置(水平)
     */
    @Builder.Default
    private HorizontalAlignment horizontalAlignment = HorizontalAlignment.CENTER;
    /**
     * 文字位置(垂直)
     */
    @Builder.Default
    private VerticalAlignment verticalAlignment = VerticalAlignment.CENTER;
    /**
     * 自动宽度
     */
    @Builder.Default
    private boolean autoWidth = false;
    /**
     * 自动换行
     */
    @Builder.Default
    private boolean autoLine = false;
    /**
     * 强制一行显示
     */
    @Builder.Default
    private boolean oneLine = false;
    /**
     * 自动大小
     */
    @Builder.Default
    private boolean autoSize = false;
    /**
     * 左边框
     */
    private boolean leftBorder;
    /**
     * 右边框
     */
    private boolean rightBorder;
    /**
     * 名称
     */
    private String name;
    /**
     * 手动换行列表,此项不为空时将进行手动换行,name失效
     */
    private String[] nameList;
    /**
     * 宽度,仅在自动宽度未生效时启用
     */
    private float width;
    /**
     * 图片,图片生效时其他属性均不生效
     */
    private PdfColumnImage columnImage;
    private PdfColumnLine columnLine;
}

图片列

@Data
@Builder
public class PdfColumnImage {
  /**
 * 图片
 */
  private final byte[] image;
  /**
 * x轴偏移位置
 */
  private float x;
  /**
 * y轴偏移位置
 */
  private float y;
  /**
 * 图片宽度
 */
  private float width;
  /**
 * 图片高度
 */
  private float height;
}

线列

@Data
@Builder
public class PdfColumnLine
{
    /**
     * 起点横坐标
     */
    private Float x1;
    /**
     * 起点纵坐标
     */
    private Float y1;
    /**
     * 控制点横坐标
     */
    private Float x2;
    /**
     * 控制点纵坐标
     */
    private Float y2;
    /**
     * 终点横坐标
     */
    private Float x3;
    /**
     * 终点纵坐标
     */
    private Float y3;
    /**
     * 线样式
     */
    @Builder.Default
    private BorderStyle borderStyle = BorderStyle.SOLID;
    /**
     * 端点样式
     */
    @Builder.Default
    private LineCapStyle lineCapStyle = LineCapStyle.BUTT;
    /**
     * 线宽
     */
    private float width;
    /**
     * 颜色
     */
    private Color color;
}

边框枚举类

public enum BorderStyle {
 /**
 * 实线
 */
 SOLID(new float[]{}, 0),
 /**
 * 虚线 线宽1,间隔1,初始偏移1
 */
 DOTTED(new float[]{1}, 1),
 /**
 * 虚线 线宽5,间隔2,初始偏移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
}

垂直对齐枚举类

public enum VerticalAlignment {
 CENTER,BOTTOM
}

线端点样式枚举类

@Getter
public enum LineCapStyle
{
    BUTT(0),
        ROUND(1),
        SQUARE(2);
    private int style;
    LineCapStyle(int style)
    {
        this.style = style;
    }
}

报告类型枚举类

public enum ReportType {
 FILE, STREAM
}

三、pdf工具类

public class DrawTableUtils
{
    private static final String FONT_BASE = "language";
    private static final String FONT = "ArialMSM.ttf";
    /**
     * 正常字体
     */
    private static final String NORMAL_FONT = "AlibabaSans-Regular.otf";
    /**
     * 加粗字体
     */
    private static final String BOLD_FONT = "AlibabaSans-Bold.otf";
    /**
     * 水平页边距
     */
    public static final float LEVEL_PADDING = 30;
    /**
     * 垂直页边距
     */
    public static final float VERTICAL_PADDING = 30;
    /**
     * 下表格线偏移
     */
    private static final float DOWN_LINE_PADDING = 0.5 f;
    private static final float SIDE_BORDER_PADDING = 1;
    /**
     * 边框宽度
     */
    private static final float BORDER_WIDTH = 1;
    /**
     * 生成PDF
     *
     * @param table pdf数据
     * @param type PDF类型
     * @throws IOException
     */
    public static ByteArrayOutputStream createDocument(PdfTable table, ReportType type, String lan) throws IOException
    {
        ByteArrayOutputStream arrayOutputStream = new ByteArrayOutputStream();
        // 初始化文档
        PDType0Font normalFont = null;
        PDType0Font boldFont = null;
        PDDocument document = new PDDocument();
        PDPage page = new PDPage(new PDRectangle(table.getWidth(), table.getHeight()));
        document.addPage(page);
        FontClass fount = getFount(document, lan);
        normalFont = fount.getNormalFont();
        boldFont = fount.getBoldFont();
        // 字体
        // String fontName = table.getFont();
        // InputStream inFont = DrawTableUtils.class.getClassLoader().getResourceAsStream(FONT);
        // PDType0Font normalFont = PDType0Font.load(document, inFont);
        // PDType0Font boldFont = null;
        // InputStream normalStream = DrawTableUtils.class.getClassLoader().getResourceAsStream(NORMAL_FONT);
        // InputStream normalStream = DrawTableUtils.class.getClassLoader().getResourceAsStream("NotoSansCJKsc-Regular.otf");
        // assert normalStream != null;
        // OpenTypeFont normalOtfFont = new OTFParser(false, true).parse(normalStream);
        // PDType0Font normalFont = PDType0Font.load(document, normalOtfFont, false);
        //
        // // 加粗字体
        // InputStream boldStream = DrawTableUtils.class.getClassLoader().getResourceAsStream(BOLD_FONT);
        // assert boldStream != null;
        // OpenTypeFont boldOtfFont = new OTFParser(false, true).parse(boldStream);
        // PDType0Font boldFont = PDType0Font.load(document, boldOtfFont, false);
        // 页
        int pageNum = 1;
        // 初始化文档位置
        Position position = new Position(LEVEL_PADDING, page.getMediaBox().getHeight() - VERTICAL_PADDING, 0);
        PDPageContentStream contentStream = new PDPageContentStream(document, page);
        for(PdfTable pdfTable: table.getTableList())
        {
            Float height = null;
            if(pdfTable.isAutoPage())
            {
                height = pdfTable.getRows().stream().map(PdfRow::getHeight).reduce(Float::sum).get();
            }
            // 强制换页
            if(pdfTable.isNextPage() || (pdfTable.isAutoPage() && position.startY - height <= VERTICAL_PADDING))
            {
                pageNum++;
                page = new PDPage(new PDRectangle(pdfTable.getWidth(), pdfTable.getHeight()));
                document.addPage(page);
                position.startY = page.getMediaBox().getHeight() - VERTICAL_PADDING;
                contentStream.close();
                contentStream = new PDPageContentStream(document, page);
            }
            for(PdfRow row: pdfTable.getRows())
            {
                // 自动行高,仅在某一列启用自动换行时生效,对空格分隔内容生效,对长度换行生效,手动换行同样生效
                row.setHeight(getHeight(row, normalFont, boldFont));
                // 分页
                if(position.startY - row.getHeight() <= VERTICAL_PADDING)
                {
                    pageNum++;
                    page = new PDPage(new PDRectangle(pdfTable.getWidth(), pdfTable.getHeight()));
                    document.addPage(page);
                    position.startY = page.getMediaBox().getHeight() - LEVEL_PADDING;
                    contentStream.close();
                    contentStream = new PDPageContentStream(document, page);
                    // if () {
                    // // 报告分页时添加下页表头
                    // if (pdfTable.getTitleRows() != null) {
                    // for (PdfRow titleRow : pdfTable.getTitleRows()) {
                    // // 自动行高,仅在某一列启用自动换行时生效,仅对空格分隔内容生效,对长度换行生效,手动换行同样生效
                    // row.setHeight(getHeight(row, normalFont, boldFont));
                    // drawLine(titleRow, document, contentStream, position, normalFont, boldFont);
                    // if (titleRow.isDownBorder()) {
                    // drawDownBorder(contentStream, page, titleRow, position);
                    // }
                    // }
                    // }
                    // }
                }
                drawLine(row, document, contentStream, position, normalFont, boldFont);
                if(row.isDownBorder())
                {
                    drawDownBorder(contentStream, page, row, position);
                }
                if(row.isUpBorder())
                {
                    drawUpBorder(contentStream, page, row, position);
                }
            }
        }
        contentStream.close();
        if(type == ReportType.FILE)
        {
            drawPageFootPage(document, pageNum, null, normalFont);
            drawPageHeadPage(document, table.getPageHead(), pageNum, normalFont);
        }
        else if(type == ReportType.STREAM)
        {
            drawPageFootPage(document, pageNum, null, normalFont);
            drawPageHeadPage(document, table.getPageHead(), pageNum, normalFont);
        }
        if(type == ReportType.FILE)
        {
            document.save("D:\\\\mypdf.pdf");
        }
        else if(type == ReportType.STREAM)
        {
            document.save(arrayOutputStream);
        }
        document.close();
        return arrayOutputStream;
    }
    /**
     * 页眉
     *
     * @param document 文档
     * @param pageHead 页眉
     * @param pageNum 文档页数
     * @param font 字体
     * @throws IOException
     */
    private static void drawPageHeadPage(PDDocument document, PdfRow pageHead, int pageNum, PDType0Font font) throws IOException
    {
        for(int i = 0; i < pageNum; i++)
        {
            Position position = new Position(0, PDRectangle.A4.getHeight(), 0);
            PDPage page = document.getPage(i);
            PDPageContentStream contentStream = new PDPageContentStream(document, page, PDPageContentStream.AppendMode.APPEND, true);
            drawLine(pageHead, document, contentStream, position, font, null);
            contentStream.close();
        }
    }
    /**
     * 生成表格下框,以行为单位
     *
     * @param contentStream 流
     * @param page 页
     * @param row 行
     * @param position 位置
     * @throws IOException
     */
    private static void drawDownBorder(PDPageContentStream contentStream, PDPage page, PdfRow row, Position position) throws IOException
    {
        contentStream.setStrokingColor(row.getBoderColor());
        contentStream.setLineWidth(BORDER_WIDTH);
        contentStream.setLineDashPattern(row.getBorderStyle().getPattern(), row.getBorderStyle().getPhase());
        contentStream.moveTo(LEVEL_PADDING, position.startY + DOWN_LINE_PADDING);
        contentStream.lineTo(page.getMediaBox().getWidth() - LEVEL_PADDING, position.startY + DOWN_LINE_PADDING);
        contentStream.stroke();
    }
    /**
     * 生成表格上边框,以行为单位
     *
     * @param contentStream
     * @param page 页
     * @param row 行
     * @param position 位置
     * @throws IOException
     */
    private static void drawUpBorder(PDPageContentStream contentStream, PDPage page, PdfRow row, Position position) throws IOException
    {
        contentStream.setStrokingColor(row.getBoderColor());
        contentStream.setLineWidth(BORDER_WIDTH);
        contentStream.setLineDashPattern(row.getBorderStyle().getPattern(), row.getBorderStyle().getPhase());
        contentStream.moveTo(LEVEL_PADDING, position.startY + row.getHeight() - DOWN_LINE_PADDING);
        contentStream.lineTo(page.getMediaBox().getWidth() - LEVEL_PADDING, position.startY + row.getHeight() - DOWN_LINE_PADDING);
        contentStream.stroke();
    }
    /**
     * 生成一行中每一列数据
     *
     * @param row 行
     * @param document 文档
     * @param contentStream 流
     * @param position 位置
     * @param normalFont 正常字体
     * @param boldFont 加粗字体
     * @throws IOException
     */
    private static void drawLine(PdfRow row, PDDocument document, PDPageContentStream contentStream, Position position, PDType0Font normalFont, PDType0Font boldFont) throws IOException
    {
        // 更新Y轴位置
        position.startY -= row.getHeight();
        for(PdfColumn column: row.getColumns())
        {
            // 添加图片
            if(column.getColumnImage() != null)
            {
                PdfColumnImage columnImage = column.getColumnImage();
                // final byte[] imageByte = IOUtils.toByteArray(Objects.requireNonNull(DrawTableUtils.class.getClassLoader().getResourceAsStream(IMAGE_PATH + columnImage.getImage())));
                final PDImageXObject image = PDImageXObject.createFromByteArray(document, columnImage.getImage(), "picture");
                contentStream.drawImage(image, position.startX + columnImage.getX(), position.startY + columnImage.getY(), columnImage.getWidth(), columnImage.getHeight());
            }
            else if(column.getColumnLine() != null)
            {
                drawLineBorder(contentStream, column, position);
            }
            else
            {
                // 背景
                if(column.getBackGround() != Color.WHITE)
                {
                    drawBackGround(row, contentStream, position, column);
                }
                // 左边框
                if(column.isLeftBorder())
                {
                    drawLeftBorder(row, contentStream, position, column);
                }
                // 右边框
                if(column.isRightBorder())
                {
                    drawRightBorder(row, contentStream, position, column);
                }
                // 列内容
                drawColumnName(row, contentStream, position, normalFont, boldFont, column);
            }
            // 更新X轴位置
            position.startX = position.startX + column.getWidth() + column.getOffset();
        }
        position.startX = LEVEL_PADDING;
    }
    /**
     * 贝赛尔曲线(二阶)
     *
     * @param contentStream
     * @param column
     * @param position
     * @throws IOException
     */
    private static void drawLineBorder(PDPageContentStream contentStream, PdfColumn column, Position position) throws IOException
    {
        PdfColumnLine columnLine = column.getColumnLine();
        // 控制点为空置为起点
        if(columnLine.getX2() == null)
        {
            columnLine.setX2(columnLine.getX1());
            columnLine.setY2(columnLine.getY1());
        }
        contentStream.setLineWidth(columnLine.getWidth());
        contentStream.setLineCapStyle(columnLine.getLineCapStyle().getStyle());
        contentStream.setLineDashPattern(columnLine.getBorderStyle().getPattern(), columnLine.getBorderStyle().getPhase());
        contentStream.setStrokingColor(columnLine.getColor());
        // 起点
        contentStream.moveTo(position.startX + columnLine.getX1(), position.startY + columnLine.getY1());
        // 贝赛尔曲线
        contentStream.curveTo(position.startX + columnLine.getX1(), position.startY + columnLine.getY1(), position.startX + columnLine.getX2(), position.startY + columnLine.getY2(), position.startX + columnLine.getX3(), position.startY + columnLine.getY3());
        contentStream.stroke();
    }
    private static void drawBackGround(PdfRow row, PDPageContentStream contentStream, Position position, PdfColumn column) throws IOException
    {
        // 背景高度,取行高
        contentStream.setLineWidth(row.getHeight());
        contentStream.setStrokingColor(column.getBackGround());
        // 实线无间隔
        contentStream.setLineDashPattern(BorderStyle.SOLID.getPattern(), BorderStyle.SOLID.getPhase());
        // 设置Y轴起始位置,背景占位为当前位置向上高度
        contentStream.moveTo(position.startX + column.getOffset(), position.startY + row.getHeight() / 2);
        contentStream.lineTo(position.startX + column.getOffset() + column.getWidth(), position.startY + row.getHeight() / 2);
        contentStream.stroke();
    }
    private static void drawColumnName(PdfRow row, PDPageContentStream contentStream, Position position, PDType0Font normalFont, PDType0Font boldFont, PdfColumn column) throws IOException
    {
        position.titleHeight = normalFont.getFontDescriptor().getCapHeight() / 1000 * column.getFontSize();
        // float titleWidth = normalFont.getStringWidth(column.getName() == null ? "" : column.getName()) / 1000 * column.getFontSize();
        float titleWidth = getStringWidth(normalFont, boldFont, column.getName() == null ? "" : column.getName(), column);
        float titleHeight = position.titleHeight;
        if(column.getNameList() != null && column.getNameList().length > 0)
        {
            // 自动换行
            int maxCeil = (int)(row.getHeight() / (titleHeight * 2.2 f));
            if(column.isAutoLine())
            {
                // 总行数
                int totalLine = 0;
                int currentLine = 0;
                // 每个字段所需行数
                boolean[] nameFlag = new boolean[column.getNameList().length];
                for(int i = 0; i < column.getNameList().length; i++)
                {
                    String name = column.getNameList()[i];
                    // 计算当前name所需行数
                    int line = getNameLineSize(normalFont, boldFont, column, name, nameFlag, i);
                    totalLine += line;
                }
                String[] splitName = new String[totalLine];
                for(int i = 0; i < column.getNameList().length; i++)
                {
                    // 字段所需行数
                    boolean flag = nameFlag[i];
                    String name = column.getNameList()[i];
                    // 获取分行数量及分行后每行数据
                    currentLine = getCurrentLineAndSplitName(normalFont, boldFont, column, flag, name, totalLine, currentLine, splitName);
                }
                // 计算显示行数
                totalLine = Math.min(totalLine, currentLine);
                totalLine = Math.min(totalLine, maxCeil);
                // 写入分行数据
                drawSplitLine(row, contentStream, position, normalFont, boldFont, column, totalLine, splitName, maxCeil);
            }
            else if(column.isOneLine())
            {
                titleWidth = 0;
                for(int i = 0; i < column.getNameList().length; i++)
                {
                    titleWidth += getStringWidth(normalFont, boldFont, column.getNameList()[i] == null ? "" : column.getNameList()[i], column);
                }
                drawTextLine(contentStream, position, column, titleWidth, row.getHeight(), normalFont, boldFont);
            }
            else
            {
                // 正常换行,非自动
                maxCeil = Math.min(maxCeil, column.getNameList().length);
                // 写入分行数据
                drawSplitLine(row, contentStream, position, normalFont, boldFont, column, maxCeil, column.getNameList(), maxCeil);
            }
        }
        else if(column.isAutoLine())
        {
            // 自动换行
            if(titleWidth > column.getWidth())
            {
                String name = column.getName();
                int maxCeil = (int)(row.getHeight() / (titleHeight * 2.2 f));
                int currentLine = 0;
                boolean[] nameFlag = new boolean[1];
                // 计算当前name所需行数
                int totalLine = getNameLineSize(normalFont, boldFont, column, name, nameFlag, 0);
                String[] splitName = new String[totalLine];
                // 获取分行数量及分行后每行数据
                currentLine = getCurrentLineAndSplitName(normalFont, boldFont, column, nameFlag[0], name, totalLine, currentLine, splitName);
                // 计算显示行数
                totalLine = Math.min(totalLine, currentLine);
                totalLine = Math.min(totalLine, maxCeil);
                // 写入分行数据
                drawSplitLine(row, contentStream, position, normalFont, boldFont, column, totalLine, splitName, maxCeil);
            }
            else
            {
                drawTextLine(contentStream, position, column, titleWidth, row.getHeight(), normalFont, boldFont);
            }
        }
        else
        {
            // 自动宽度
            if(column.isAutoWidth())
            {
                column.setWidth(titleWidth);
            }
            drawTextLine(contentStream, position, column, titleWidth, row.getHeight(), normalFont, boldFont);
        }
    }
    private static void drawRightBorder(PdfRow row, PDPageContentStream contentStream, Position position, PdfColumn column) throws IOException
    {
        // 设置宽度
        contentStream.setLineWidth(BORDER_WIDTH);
        contentStream.setStrokingColor(column.getBorderColor());
        // 实线无间隔
        contentStream.setLineDashPattern(BorderStyle.SOLID.getPattern(), BorderStyle.SOLID.getPhase());
        // 设置左边框位置,与背景色对齐
        contentStream.moveTo(position.startX + column.getOffset() + column.getWidth(), position.startY);
        contentStream.lineTo(position.startX + column.getOffset() + column.getWidth(), position.startY + row.getHeight());
        contentStream.stroke();
    }
    private static void drawLeftBorder(PdfRow row, PDPageContentStream contentStream, Position position, PdfColumn column) throws IOException
    {
        // 设置宽度
        contentStream.setLineWidth(BORDER_WIDTH);
        contentStream.setStrokingColor(column.getBorderColor());
        // 实线无间隔
        contentStream.setLineDashPattern(BorderStyle.SOLID.getPattern(), BorderStyle.SOLID.getPhase());
        // 设置左边框位置,与背景色对齐
        contentStream.moveTo(position.startX + column.getOffset(), position.startY);
        contentStream.lineTo(position.startX + column.getOffset(), position.startY + row.getHeight());
        contentStream.stroke();
    }
    /**
     * 写入分行数据
     *
     * @param row 当前行信息
     * @param contentStream 流
     * @param position 位置
     * @param normalFont 正常字体
     * @param column 列
     * @param totalLine 分行后总行数
     * @param splitName 分行后每行内容
     * @param maxCeil 最大行数
     * @throws IOException
     */
    private static void drawSplitLine(PdfRow row, PDPageContentStream contentStream, Position position, PDType0Font normalFont, PDType0Font boldFont, PdfColumn column, int totalLine, String[] splitName, int maxCeil) throws IOException
    {
        int currentCel = totalLine;
        // 分行后单行行高
        float hi = row.getHeight() / totalLine;
        for(String cellName: splitName)
        {
            // 写入分行数据
            Position aPosition = new Position(position.startX, position.startY + hi * (--currentCel), position.getTitleHeight());
            PdfColumn aColumn = PdfColumn.builder().horizontalAlignment(column.getHorizontalAlignment()).fontSize(column.isAutoSize() ? column.getFontSize() / maxCeil * 1.8 f : column.getFontSize()).name(cellName).width(column.getWidth()).offset(column.getOffset()).block(column.isBlock()).build();
            // float pWidth = normalFont.getStringWidth(aColumn.getName() == null ? "" : aColumn.getName()) / 1000 * aColumn.getFontSize();
            float pWidth = getStringWidth(normalFont, boldFont, aColumn.getName() == null ? "" : aColumn.getName(), aColumn);
            drawTextLine(contentStream, aPosition, aColumn, pWidth, hi, normalFont, boldFont);
            if(currentCel == 0)
            {
                break;
            }
        }
    }
    /**
     * 获取分行后行数及每行内容
     *
     * @param normalFont 字体
     * @param column 列
     * @param flag 分行标志 true 按长度划分,false 按空格划分
     * @param name 需要分行的列名
     * @param totalLine 总行数
     * @param splitName 记录分行后每行信息
     * @return
     * @throws IOException
     */
    private static int getCurrentLineAndSplitName(PDType0Font normalFont, PDType0Font boldFont, PdfColumn column, boolean flag, String name, int totalLine, int currentLine, String[] splitName) throws IOException
    {
        float sWidth = 0;
        StringBuilder builder = new StringBuilder();
        // 按长度换行
        if(flag)
        {
            for(int j = 0; j < name.length(); j++)
            {
                String s = name.substring(j, j + 1);
                // sWidth += normalFont.getStringWidth(s) / 1000 * column.getFontSize();
                sWidth += getStringWidth(normalFont, boldFont, s, column);
                if(sWidth > column.getWidth())
                {
                    // 记录分行数据
                    if(currentLine == totalLine)
                    {
                        break;
                    }
                    splitName[currentLine++] = builder.toString();
                    // 换行后以当前字符为初始值,清空builder,重新赋值
                    // sWidth = normalFont.getStringWidth(s) / 1000 * column.getFontSize();
                    sWidth = getStringWidth(normalFont, boldFont, s, column);
                    builder.setLength(0);
                    builder.append(s);
                }
                else
                {
                    builder.append(s);
                }
            }
        }
        else
        {
            // 按空格换行
            String[] split = name.split(" ");
            for(int j = 0; j < split.length; j++)
            {
                String s = split[j] + (j == split.length - 1 ? "" : " ");
                // sWidth += normalFont.getStringWidth(s + (j == split.length - 1 ? "" : " ")) / 1000 * column.getFontSize();
                sWidth += getStringWidth(normalFont, boldFont, s, column);
                if(sWidth > column.getWidth())
                {
                    // 记录分行数据
                    if(currentLine == totalLine)
                    {
                        break;
                    }
                    splitName[currentLine++] = builder.toString();
                    // 换行后以当前字符为初始值,清空builder,重新赋值
                    // sWidth = normalFont.getStringWidth(s) / 1000 * column.getFontSize();
                    sWidth = getStringWidth(normalFont, boldFont, s, column);
                    builder.setLength(0);
                    builder.append(s);
                }
                else
                {
                    builder.append(s);
                }
            }
        }
        // 只有一行数据
        if(currentLine < totalLine)
        {
            splitName[currentLine++] = builder.toString();
        }
        return currentLine;
    }
    /**
     * 获取当前列名可分行数量
     *
     * @param normalFont 字体
     * @param column 列
     * @param name 列名
     * @param nameFlag 分行标志 true 按长度划分,false 按空格划分
     * @param currentNameNo 当前处理列内行号
     * @return
     * @throws IOException
     */
    private static int getNameLineSize(PDType0Font normalFont, PDType0Font boldFont, PdfColumn column, String name, boolean[] nameFlag, Integer currentNameNo) throws IOException
    {
        boolean flag = false;
        float len = 0;
        int line = 1;
        float lineLength;
        // 按空格切分
        String[] split = name.split(" ");
        // 按空格换行
        for(int j = 0; j < split.length; j++)
        {
            // lineLength = normalFont.getStringWidth(split[j] + (j == split.length - 1 ? "" : " ")) / 1000 * column.getFontSize();
            lineLength = getStringWidth(normalFont, boldFont, split[j] + (j == split.length - 1 ? "" : " "), column);
            len += lineLength;
            if(len > column.getWidth())
            {
                len = lineLength;
                line++;
            }
            if(lineLength > column.getWidth())
            {
                flag = true;
                break;
            }
        }
        if(nameFlag != null)
        {
            nameFlag[currentNameNo] = flag;
        }
        // 按空格换行失败使用按长度平均分换行
        if(flag)
        {
            // 总长度
            // lineLength = normalFont.getStringWidth(name) / 1000 * column.getFontSize();
            lineLength = getStringWidth(normalFont, boldFont, name, column);
            // 所需行数
            line = (int) Math.ceil(lineLength / column.getWidth());
        }
        return line;
    }
    /**
     * 计算行高,以空格切分数据,空格不成改为长度切分
     *
     * @param row 行
     * @param normalFont 字体
     * @return float 当前行高度
     */
    @SneakyThrows
    private static float getHeight(PdfRow row, PDType0Font normalFont, PDType0Font boldFont)
    {
        float height = row.getHeight();
        int size = 0;
        if(row.isAutoHeight())
        {
            for(PdfColumn column: row.getColumns())
            {
                if(column.isAutoLine())
                {
                    float titleHeight = normalFont.getFontDescriptor().getCapHeight() / 1000 * column.getFontSize();
                    if(column.getNameList() != null)
                    {
                        size = 0;
                        for(int i = 0; i < column.getNameList().length; i++)
                        {
                            String name = column.getNameList()[i];
                            // 计算当前name所需行数
                            size += getNameLineSize(normalFont, boldFont, column, name, null, i);
                        }
                    }
                    else if(StringUtils.isNotEmpty(column.getName()))
                    {
                        size = getNameLineSize(normalFont, boldFont, column, column.getName(), null, 0);
                    }
                    height = Math.max(height, (titleHeight * 2.2 f) * size);
                }
            }
        }
        return height;
    }
    /**
     * 页脚页数编码
     *
     * @param document 文档
     * @param pageNum 页面数
     * @param normalFont 字体
     * @throws IOException
     */
    private static void drawPageFootPage(PDDocument document, int pageNum, String name, PDType0Font normalFont) throws IOException
    {
        PdfRow row;
        Position position = new Position(0, 5, 0);
        for(int i = 0; i < pageNum; i++)
        {
            PDPage page = document.getPage(i);
            // float unitWidth = (page.getMediaBox().getWidth() - LEVEL_PADDING * 2) / 100;
            row = PdfRow.builder().height(0).columns(new ArrayList < > ()).build();
            // row.addColumn(PdfColumn.builder().name("BMC Medical Co., Ltd.").width(unitWidth * 33).horizontalAlignment(HorizontalAlignment.LEFT).build());
            // row.addColumn(PdfColumn.builder().name("BMCares App - iCode " + name).width(unitWidth * 33).horizontalAlignment(HorizontalAlignment.CENTER).build());
            row.addColumn(PdfColumn.builder().name((i + 1) + "" + pageNum).width(page.getMediaBox().getWidth()).horizontalAlignment(HorizontalAlignment.CENTER).verticalAlignment(VerticalAlignment.BOTTOM).build());
            row.addColumn(PdfColumn.builder().columnLine(PdfColumnLine.builder().x1(-page.getMediaBox().getWidth()).y1(VERTICAL_PADDING - 10).x3(0 f).y3(VERTICAL_PADDING - 10).width(1 f).color(new Color(56, 165, 160)).build()).build());
            PDPageContentStream contentStream = new PDPageContentStream(document, page, PDPageContentStream.AppendMode.APPEND, true);
            position.setStartX(0);
            position.setStartY(5);
            drawLine(row, document, contentStream, position, normalFont, null);
            // contentStream.beginText();
            // contentStream.setFont(font, 9);
            // contentStream.setNonStrokingColor(Color.GRAY);
            // contentStream.newLineAtOffset(35, 25);
            // contentStream.showText(text + (i + 1) + "" + pageNum);
            // contentStream.endText();
            contentStream.close();
        }
    }
    /**
     * @param contentStream
     * @param position
     * @param column
     * @param titleWidth
     * @param rowHeight
     * @param normalFont
     * @param boldFont
     * @throws IOException
     */
    private static void drawTextLine(PDPageContentStream contentStream, Position position, PdfColumn column, float titleWidth, float rowHeight, PDType0Font normalFont, PDType0Font boldFont) throws IOException
    {
        // 文字
        contentStream.beginText();
        contentStream.setFont(normalFont, column.getFontSize());
        contentStream.setNonStrokingColor(column.getTextColor());
        // 加粗,使用粗体文字
        if(column.isBlock())
        {
            contentStream.setFont(boldFont, column.getFontSize());
        }
        HorizontalAlignment horizontalAlignment = column.getHorizontalAlignment();
        VerticalAlignment verticalAlignment = column.getVerticalAlignment();
        // 自动截断
        if(titleWidth > column.getWidth())
        {
            float length = 0;
            int i = 0;
            float latestLength = 0;
            StringBuilder builder = new StringBuilder();
            float sWidth = 0;
            if(column.getNameList() != null)
            {
                // 计算长度超长位置
                String[] nameList = column.getNameList();
                for(; i < nameList.length; i++)
                {
                    String name = nameList[i];
                    latestLength = getStringWidth(normalFont, boldFont, name, column);
                    length += latestLength;
                    if(length >= column.getWidth())
                    {
                        break;
                    }
                }
                // 计算超长位置字符
                String name = nameList[i];
                for(int j = 0; j < name.length(); j++)
                {
                    String s = name.substring(j, j + 1);
                    sWidth += getStringWidth(normalFont, boldFont, s, column);
                    if(sWidth >= column.getWidth() - length + latestLength)
                    {
                        titleWidth = sWidth - getStringWidth(normalFont, boldFont, s, column);
                        break;
                    }
                    else
                    {
                        builder.append(s);
                    }
                }
                nameList[i] = builder.toString();
                // 重置后续部分内容
                for(++i; i < nameList.length; i++)
                {
                    nameList[i] = "";
                }
            }
            else
            {
                // 计算超长位置字符
                String name = column.getName();
                for(int j = 0; j < name.length(); j++)
                {
                    String s = name.substring(j, j + 1);
                    sWidth += getStringWidth(normalFont, boldFont, s, column);
                    if(sWidth >= column.getWidth())
                    {
                        titleWidth = sWidth - getStringWidth(normalFont, boldFont, s, column);
                        break;
                    }
                    else
                    {
                        builder.append(s);
                    }
                }
                column.setName(builder.toString());
            }
        }
        float x = 0, y = 0;
        if(horizontalAlignment == HorizontalAlignment.CENTER)
        {
            // 居中
            x = (column.getWidth() - titleWidth) / 2 + position.startX + column.getOffset();
        }
        else if(horizontalAlignment == HorizontalAlignment.LEFT)
        {
            // 居左
            x = position.startX + column.getOffset();
        }
        else if(horizontalAlignment == HorizontalAlignment.RIGHT)
        {
            // 居右
            x = position.startX + column.getOffset() + column.getWidth() - titleWidth;
        }
        if(verticalAlignment == VerticalAlignment.BOTTOM)
        {
            // 底部
            y = position.startY + position.titleHeight / 2;
        }
        else if(verticalAlignment == VerticalAlignment.CENTER)
        {
            // 居中
            y = position.startY + rowHeight / 2 - position.titleHeight / 2;
        }
        contentStream.newLineAtOffset(x, y);
        if(column.getNameList() != null)
        {
            String[] nameList = column.getNameList();
            for(int i = 0; i < nameList.length; i++)
            {
                String name = nameList[i];
                if(column.getTextColorList() != null && i < column.getTextColorList().length)
                {
                    contentStream.setNonStrokingColor(column.getTextColorList()[i]);
                }
                contentStream.showText(name == null ? "" : name);
            }
        }
        else
        {
            contentStream.showText(column.getName() == null ? "" : column.getName());
        }
        contentStream.endText();
        // 加粗使用偏移方法
        // if (column.isBlock()) {
        // drawBlockText(contentStream, position, column, titleWidth, rowHeight, x, y);
        // }
    }
    /**
     * 加粗字体,偏移实现
     *
     * @param contentStream
     * @param position
     * @param pdfColumn
     * @param titleWidth
     * @param rowHeight
     * @throws IOException
     */
    private static void drawBlockText(PDPageContentStream contentStream, Position position, PdfColumn pdfColumn, float titleWidth, float rowHeight, float x, float y) throws IOException
    {
        float offset = pdfColumn.getFontSize() / 100;
        // if (pdfColumn.getHorizontalAlignment() == HorizontalAlignment.CENTER) {
        // // 居中
        // x = (pdfColumn.getWidth() - titleWidth) / 2 + position.startX + pdfColumn.getOffset();
        // y = position.startY - position.titleHeight / 2 + rowHeight / 2;
        // } else if (pdfColumn.getHorizontalAlignment() == HorizontalAlignment.LEFT) {
        // // 居左
        // x = position.startX + pdfColumn.getOffset();
        // y = position.startY - position.titleHeight / 2 + rowHeight / 2;
        // } else if (pdfColumn.getHorizontalAlignment() == HorizontalAlignment.RIGHT) {
        // // 居右
        // x = position.startX + pdfColumn.getOffset() + pdfColumn.getWidth() - titleWidth;
        // y = position.startY - position.titleHeight / 2 + rowHeight / 2;
        // // offset = -offset;
        // }
        // 左上
        contentStream.beginText();
        contentStream.newLineAtOffset(x - offset, y + offset);
        contentStream.showText(pdfColumn.getName() == null ? "" : pdfColumn.getName());
        contentStream.endText();
        // 左
        contentStream.beginText();
        contentStream.newLineAtOffset(x - offset, y);
        contentStream.showText(pdfColumn.getName() == null ? "" : pdfColumn.getName());
        contentStream.endText();
        // 左下
        contentStream.beginText();
        contentStream.newLineAtOffset(x - offset, y - offset);
        contentStream.showText(pdfColumn.getName() == null ? "" : pdfColumn.getName());
        contentStream.endText();
        // 上
        contentStream.beginText();
        contentStream.newLineAtOffset(x, y + offset);
        contentStream.showText(pdfColumn.getName() == null ? "" : pdfColumn.getName());
        contentStream.endText();
        // 下
        contentStream.beginText();
        contentStream.newLineAtOffset(x, y - offset);
        contentStream.showText(pdfColumn.getName() == null ? "" : pdfColumn.getName());
        contentStream.endText();
        // 右上
        contentStream.beginText();
        contentStream.newLineAtOffset(x + offset, y + offset);
        contentStream.showText(pdfColumn.getName() == null ? "" : pdfColumn.getName());
        contentStream.endText();
        // 右
        contentStream.beginText();
        contentStream.newLineAtOffset(x + offset, y);
        contentStream.showText(pdfColumn.getName() == null ? "" : pdfColumn.getName());
        contentStream.endText();
        // 右下
        contentStream.beginText();
        contentStream.newLineAtOffset(x + offset, y - offset);
        contentStream.showText(pdfColumn.getName() == null ? "" : pdfColumn.getName());
        contentStream.endText();
    }
    private static FontClass getFount(PDDocument document, String language)
    {
        // Locale locale;
        FontClass fontClass = new FontClass();
        String normalFontName;
        String boldFontName;
        // if (StringUtils.isBlank(language)) {
        // locale = LocaleContextHolder.getLocale();
        // } else {
        // locale = new Locale(language);
        // }
        //
        // switch (locale.getLanguage()) {
        // case "ja": {
        // normalFontName = "AlibabaSansJP-Regular.ttf";
        // boldFontName = "AlibabaSansJP-Bold.ttf";
        // break;
        // }
        // case "zh": {
        // normalFontName = "AlibabaPuHuiTi-Regular.ttf";
        // boldFontName = "AlibabaPuHuiTi-Bold.ttf";
        // break;
        // }
        // case "ko": {
        // normalFontName = "AlibabaSansKR-Regular.ttf";
        // boldFontName = "AlibabaSansKR-Bold.ttf";
        // break;
        // }
        // case "th": {
        // normalFontName = "AlibabaSansThai-Regular.ttf";
        // boldFontName = "AlibabaSansThai-Bold.ttf";
        // break;
        // }
        // case "vi": {
        // normalFontName = "AlibabaSansViet-Regular.ttf";
        // boldFontName = "AlibabaSansViet-Bold.ttf";
        // break;
        // }
        // default: {
        normalFontName = "AlibabaSans-Regular.ttf";
        boldFontName = "AlibabaSans-Bold.ttf";
        // }
        // }
        InputStream inNFont = DrawTableUtils.class.getClassLoader().getResourceAsStream(FONT_BASE + normalFontName);
        InputStream inBFont = DrawTableUtils.class.getClassLoader().getResourceAsStream(FONT_BASE + boldFontName);
        try
        {
            fontClass.setNormalFont(PDType0Font.load(document, inNFont));
            fontClass.setBoldFont(PDType0Font.load(document, inBFont));
        }
        catch (IOException e)
        {
            // log.error("font not found");
            throw new RuntimeException(e);
        }
        return fontClass;
    }
    private static float getStringWidth(PDType0Font normalFount, PDType0Font boldFount, String name, PdfColumn column)
    {
        try
        {
            if(column.isBlock())
            {
                if(boldFount != null)
                {
                    return boldFount.getStringWidth(name) / 1000 * column.getFontSize();
                }
                else
                {
                    return normalFount.getStringWidth(name) / 1000 * column.getFontSize() + column.getFontSize() / 10;
                }
            }
            else
            {
                return normalFount.getStringWidth(name) / 1000 * column.getFontSize();
            }
        }
        catch (IOException e)
        {
            throw new RuntimeException(e);
        }
    }
    @Data
    @AllArgsConstructor
    static class Position
    {
        float startX;
        float startY;
        float titleHeight;
    }
    @Data
    static class FontClass
    {
        PDType0Font normalFont;
        PDType0Font boldFont;
    }
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值