一、优化
此次修改优化了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;
}
}

3260

被折叠的 条评论
为什么被折叠?



