com.janeluo.easypdf.PDFDoc Maven / Gradle / Ivy
/* Copyright (c) 2021 janeluo
* easy-pdf is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
package com.janeluo.easypdf;
import com.itextpdf.io.font.PdfEncodings;
import com.itextpdf.io.image.ImageDataFactory;
import com.itextpdf.kernel.colors.DeviceRgb;
import com.itextpdf.kernel.events.Event;
import com.itextpdf.kernel.events.IEventHandler;
import com.itextpdf.kernel.events.PdfDocumentEvent;
import com.itextpdf.kernel.font.PdfFont;
import com.itextpdf.kernel.font.PdfFontFactory;
import com.itextpdf.kernel.geom.PageSize;
import com.itextpdf.kernel.pdf.*;
import com.itextpdf.kernel.pdf.canvas.PdfCanvas;
import com.itextpdf.kernel.pdf.xobject.PdfFormXObject;
import com.itextpdf.layout.Document;
import com.itextpdf.layout.borders.Border;
import com.itextpdf.layout.element.*;
import com.itextpdf.layout.property.TextAlignment;
import com.itextpdf.layout.property.UnitValue;
import com.itextpdf.layout.property.VerticalAlignment;
import com.itextpdf.layout.splitting.ISplitCharacters;
import com.janeluo.easypdf.draw.CustomLineSeparator;
import lombok.extern.slf4j.Slf4j;
import org.xml.sax.Attributes;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* PDF 操作类
*
* 这个类封装 PDF 文档相关的操作,通过 iText 实现。
* 如果需要水印、印章等特殊效果,请参考 PDFProcess 类。
*/
@Slf4j
public class PDFDoc extends TextDoc {
protected InputStream templateInputStream;
protected Map fontFamilyMap;
private final Map blockTypes = new HashMap() {{
put("title", BlockType.BLOCK_TITLE);
put("chapter", BlockType.BLOCK_CHAPTER);
put("section", BlockType.BLOCK_SECTION);
put("para", BlockType.BLOCK_PARA);
}};
private final List pdfBlockDefaults;
private PdfDocument pdfDocument;
private Document document;
private final Map images;
private final ISplitCharacters splitCharacters = (glyphLine, i) -> true;
public PDFDoc(InputStream templateInputStream, OutputStream outputStream, Map fontFamilyMap) {
super(outputStream);
this.templateInputStream = templateInputStream;
this.fontFamilyMap = fontFamilyMap;
this.fontFamilyMap.put("heiti", "font/SIMHEI.TTF");
this.fontFamilyMap.put("hei", "font/SIMHEI.TTF");
this.fontFamilyMap.put("songti", "font/SIMSUN.TTC,0");
this.fontFamilyMap.put("song", "font/SIMSUN.TTC,0");
pdfBlockDefaults = new ArrayList<>();
images = new HashMap<>();
for (Map.Entry entry : this.fontFamilyMap.entrySet()) {
pdfBlockDefaults.add(new PDFBlockDefault(BlockType.BLOCK_TITLE,
entry.getKey(), 18, FontStyle.BOLD,
TextAlignment.CENTER, 0.0f, 0.0f, 16.0f)
);
pdfBlockDefaults.add(new PDFBlockDefault(BlockType.BLOCK_CHAPTER,
entry.getKey(), 16, FontStyle.BOLD,
TextAlignment.LEFT, 0.0f, 14.0f, 0.0f)
);
pdfBlockDefaults.add(new PDFBlockDefault(BlockType.BLOCK_SECTION,
entry.getKey(), 14, FontStyle.BOLD,
TextAlignment.LEFT, 0.0f, 12.0f, 0.0f)
);
pdfBlockDefaults.add(new PDFBlockDefault(BlockType.BLOCK_PARA,
entry.getKey(), 12, FontStyle.NONE,
TextAlignment.LEFT, 22.0f, 6.0f, 0.0f)
);
// 默认的块属性,应用程序可以通过 setBlockDefault() 来修改这些属性
}
}
private void addMetaInfo() {
PdfDocumentInfo info = pdfDocument.getDocumentInfo();
// info.setTitle("TextPdf 合同");
// info.setSubject("本合同带有防伪标识,请登录系统核查");
// info.setAuthor("Lucky Byte, Inc.(诺百)");
// info.setKeywords("TextPdf, PDF, Lucky Byte Inc., 诺百");
// info.setCreator("TextPdf 版本 " + Version.VERSION +
// " - http://git.oschina.net/lucky-byte/textpdf");
}
@Override
public boolean open() {
try {
final PdfWriter writer = new PdfWriter(outputStream);
// 有模板
if (this.templateInputStream != null) {
PdfDocument srcDoc = new PdfDocument(new PdfReader(this.templateInputStream));
// Event handler copies content of the source pdf file on every page
// of the result pdf file
final PdfPage firstPage = srcDoc.getFirstPage();
PageSize pageSize = new PageSize(firstPage.getPageSize().getWidth(), firstPage.getPageSize().getHeight());
pdfDocument = new PdfDocument(writer);
pdfDocument.setDefaultPageSize(pageSize);
final PdfFormXObject background = firstPage.copyAsFormXObject(pdfDocument);
pdfDocument.addEventHandler(PdfDocumentEvent.END_PAGE,
new PaginationEventHandler(background));
} else {
pdfDocument = new PdfDocument(writer);
}
this.document = new Document(pdfDocument);
document.setMargins(pageMarginTop, pageMarginRight, pageMarginBottom, pageMarginLeft);
// writer.setFullCompression(); // 需求 PDF 1.5
writer.setCompressionLevel(9);
addMetaInfo();
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
protected class PaginationEventHandler implements IEventHandler {
protected PdfFormXObject background;
public PaginationEventHandler(PdfFormXObject background) {
this.background = background;
}
@Override
public void handleEvent(Event event) {
PdfDocument pdfDoc = ((PdfDocumentEvent) event).getDocument();
PdfPage currentPage = ((PdfDocumentEvent) event).getPage();
// Add the background
final PdfCanvas pdfCanvas = new PdfCanvas(currentPage.newContentStreamBefore(), currentPage.getResources(), pdfDoc);
pdfCanvas
.addXObjectAt(background, 0, 0);
}
}
@Override
public void close() {
pdfDocument.close();
}
@Override
public boolean isOpen() {
if (pdfDocument == null) {
return false;
}
return !pdfDocument.isClosed();
}
@Override
public void setPageSize(PageSize pageSize) {
super.setPageSize(pageSize);
if (isOpen()) {
pdfDocument.addNewPage(pageSize);
}
}
@Override
public void setPageMargin(int left, int right, int top, int bottom) {
super.setPageMargin(left, right, top, bottom);
if (isOpen()) {
document.setMargins(pageMarginTop, pageMarginRight, pageMarginBottom, pageMarginLeft);
}
}
/**
* 设置块默认属性
* 这个函数一次性设置所有的块默认属性,如果需要单独设置某一个属性,
* 请使用下面的 setBlockDefaultXXX() 函数。
*
* @param blockType 块类型
* @param fontFamily 字体家族
* @param fontSize 字体大小
* @param fontStyle 字体风格
* @param alignment 对齐方式
* @param indent 首行缩进距离
*/
public void setBlockDefault(BlockType blockType, String fontFamily,
int fontSize, FontStyle fontStyle, TextAlignment alignment, float indent,
float lineSpaceBefore, float lineSpaceAfter) {
for (PDFBlockDefault block : pdfBlockDefaults) {
if (block.blockType == blockType) {
block.fontFamily = fontFamily;
block.fontSize = fontSize;
block.fontStyle = fontStyle;
block.alignment = alignment;
block.indent = indent;
block.lineSpaceBefore = lineSpaceBefore;
block.lineSpaceAfter = lineSpaceAfter;
break;
}
}
}
/**
* 设置块的默认字体家族
*
* @param blockType 类型
* @param fontFamily 字体
*/
public void setBlockDefaultFontFamily(BlockType blockType, String fontFamily) {
for (PDFBlockDefault block : pdfBlockDefaults) {
if (block.blockType == blockType) {
block.fontFamily = fontFamily;
break;
}
}
}
/**
* 设置块的默认字体大小
*
* @param blockType 类型
* @param fontSize 字体大小
*/
public void setBlockDefaultFontSize(BlockType blockType, int fontSize) {
for (PDFBlockDefault block : pdfBlockDefaults) {
if (block.blockType == blockType) {
block.fontSize = fontSize;
break;
}
}
}
/**
* 设置块的默认字体风格
*
* @param blockType 类型
* @param fontStyle 字体样式
*/
public void setBlockDefaultFontStyle(BlockType blockType, FontStyle fontStyle) {
for (PDFBlockDefault block : pdfBlockDefaults) {
if (block.blockType == blockType) {
block.fontStyle = fontStyle;
break;
}
}
}
/**
* 设置块的默认对齐方式
*
* @param blockType 类型
* @param alignment 对齐方式
*/
public void setBlockDefaultAlignment(BlockType blockType, TextAlignment alignment) {
for (PDFBlockDefault block : pdfBlockDefaults) {
if (block.blockType == blockType) {
block.alignment = alignment;
break;
}
}
}
/**
* 设置块的默认首行缩进距离
*
* @param blockType 类型
* @param indent 首航缩进大小
*/
public void setBlockDefaultIndent(BlockType blockType, float indent) {
for (PDFBlockDefault block : pdfBlockDefaults) {
if (block.blockType == blockType) {
block.indent = indent;
break;
}
}
}
/**
* 设置段前空间
*
* @param blockType 类型
* @param lineSpaceBefore 行上面空行大小
*/
public void setBlockDefaultLineSpaceBefore(BlockType blockType, float lineSpaceBefore) {
for (PDFBlockDefault block : pdfBlockDefaults) {
if (block.blockType == blockType) {
block.lineSpaceBefore = lineSpaceBefore;
break;
}
}
}
/**
* 设置段后空间
*
* @param blockType 类型
* @param lineSpaceAfter 下面空行大小
*/
public void setBlockDefaultLineSpaceAfter(BlockType blockType, float lineSpaceAfter) {
for (PDFBlockDefault block : pdfBlockDefaults) {
if (block.blockType == blockType) {
block.lineSpaceAfter = lineSpaceAfter;
break;
}
}
}
/**
* 根据 TextChunk 中字体相关的属性来设置 Chunk 的字体,字体包括:
* 家族(黑体或宋体)、大小、修饰(粗体、斜体、下划线等等)。
*
* @param textChunk TextChunk 对象,保存了字体的属性
* @param chunk PDF Chunk 对象
* @param blockDefault
* @throws IOException
*/
private void setChunkFont(TextChunk textChunk, Text chunk,
PDFBlockDefault blockDefault) throws IOException {
Map attrs = textChunk.getAttrs();
String fontFamily = blockDefault.fontFamily;
int fontSize = blockDefault.fontSize;
FontStyle fontStyle = blockDefault.fontStyle;
PdfFont pdfFont = null;
String value = attrs.get("font-family");
if (value != null) {
fontFamily = value;
}
value = attrs.get("font-size");
if (value != null) {
try {
fontSize = Integer.parseInt(value);
} catch (Exception ex) {
System.err.println("Font size '" + value + "' invalid.");
}
}
value = attrs.get("font-style");
if (value != null) {
String[] styles = value.split(",");
for (String style : styles) {
String label = style.trim();
if ("bold".equalsIgnoreCase(label)) {
chunk.setBold();
} else if ("italic".equalsIgnoreCase(label)) {
chunk.setItalic();
} else if ("underline".equalsIgnoreCase(label)) {
chunk.setUnderline();
}
}
} else {
switch (fontStyle) {
case BOLD:
chunk.setBold();
break;
case ITALIC:
chunk.setItalic();
break;
case UNDERLINE:
chunk.setUnderline();
break;
case NONE:
default:
break;
}
}
String fontProgram = fontFamilyMap.get(fontFamily);
pdfFont = PdfFontFactory.createFont(fontProgram,
PdfEncodings.IDENTITY_H, PdfFontFactory.EmbeddingStrategy.PREFER_EMBEDDED);
chunk.setFontSize(fontSize);
chunk.setFont(pdfFont);
}
/**
* 根据 TextChunk 的属性生成 PDF Text 对象
*
* @param text_chunk TextChunk 对象
* @param blockDefault 块默认类型
* @return PDF Text
*/
private Text formatChunk(TextChunk text_chunk,
PDFBlockDefault blockDefault) {
Text chunk = new Text("");
Map attrs = text_chunk.getAttrs();
String value = attrs.get("super");
if ("true".equalsIgnoreCase(value)) {
chunk.setTextRise(6.0f);
if (!attrs.containsKey("font-size")) {
attrs.put("font-size", "8");
}
}
value = attrs.get("sub");
if ("true".equalsIgnoreCase(value)) {
chunk.setTextRise(-3.0f);
if (!attrs.containsKey("font-size")) {
attrs.put("font-size", "8");
}
}
String contents = text_chunk.getContents();
value = text_chunk.getAttrs().get("minlen");
if (value != null && value.length() > 0) {
if (contents.length() == 0) {
chunk.setUnderline(1.0f, -4.0f);
}
try {
int minlen = Integer.parseInt(value);
int currlen = 0;
for (int i = 0; i < contents.length(); i++) {
char ch = contents.charAt(i);
if (ch < 127) {
currlen += 1;
} else {
currlen += 2;
}
}
if (currlen < minlen) {
StringBuilder builder = new StringBuilder(contents);
for (; currlen < minlen; currlen++) {
builder.append(' ');
}
contents = builder.toString();
}
} catch (Exception ex) {
ex.printStackTrace();
System.err.println("minlen need a integer value.");
}
}
chunk.setText(contents);
try {
setChunkFont(text_chunk, chunk, blockDefault);
} catch (IOException ignored) {
}
return chunk;
}
private void formatParagraph(Paragraph para, List chunkList) {
// 用第一个节点来设置块的段落属性
TextChunk textChunk = chunkList.get(0);
if (textChunk != null) {
Map attrs = textChunk.getAttrs();
// 设置段落对齐方式
String value = attrs.get("align");
if (value != null) {
if ("left".equalsIgnoreCase(value)) {
para.setTextAlignment(TextAlignment.LEFT);
} else if ("center".equalsIgnoreCase(value)) {
para.setTextAlignment(TextAlignment.CENTER);
} else if ("right".equalsIgnoreCase(value)) {
para.setTextAlignment(TextAlignment.RIGHT);
} else {
System.err.println("Block alignment type '"
+ value + "' unknown.");
}
}
// 设置段落缩进
value = attrs.get("indent");
if (value != null) {
try {
float indent = Float.parseFloat(value);
para.setFirstLineIndent(indent);
} catch (Exception ex) {
System.err.println(
"Indent attribute must has a float value");
}
}
// 设置段落前空间
value = attrs.get("space-before");
if (value != null) {
try {
float space = Float.parseFloat(value);
para.setMarginTop(space);
} catch (Exception ex) {
System.err.println(
"space-before attribute must has a float value");
}
}
// 设置段落后空间
value = attrs.get("space-after");
if (value != null) {
try {
float space = Float.parseFloat(value);
para.setMarginBottom(space);
} catch (Exception ex) {
if (log.isErrorEnabled()) {
log.error("space-after attribute must has a float value", ex);
} else {
System.err.println(
"space-after attribute must has a float value");
}
}
}
final String height = attrs.get("height");
if (height != null && !"".equals(height)) {
para.setHeight(Float.parseFloat(height));
}
// 外补丁
final String margin = attrs.get("margin");
if (margin != null) {
final String[] split = margin.split(" ");
try {
if (split.length == 1) {
para.setMargin(Float.parseFloat(margin));
} else if (split.length == 2) {
float top = Float.parseFloat(split[0]), bottom = Float.parseFloat(split[0]);
float left = Float.parseFloat(split[1]), right = Float.parseFloat(split[1]);
para.setMargins(top, right, bottom, left);
}
if (split.length == 4) {
float top = Float.parseFloat(split[0]);
float right = Float.parseFloat(split[1]);
float bottom = Float.parseFloat(split[2]);
float left = Float.parseFloat(split[3]);
para.setMargins(top, right, bottom, left);
}
} catch (Exception ex) {
if (log.isErrorEnabled()) {
log.error("margin attribute must has a float value", ex);
} else {
System.err.println(
"margin attribute must has a float value");
}
}
}
// 相对定位, 格式左上右下
final String relativePosition = attrs.get("relative-position");
if (relativePosition != null && !"".equals(relativePosition)) {
final String[] split = relativePosition.split(" ");
if (split.length == 4) {
try {
float left = Float.parseFloat(split[0]);
float top = Float.parseFloat(split[1]);
float right = Float.parseFloat(split[2]);
float bottom = Float.parseFloat(split[3]);
para.setRelativePosition(left, top, right, bottom);
} catch (Exception ex) {
if (log.isErrorEnabled()) {
log.error("relative-position attribute must has a float value", ex);
} else {
System.err.println(
"relative-position attribute must has a float value");
}
}
} else {
if (log.isErrorEnabled()) {
log.error("relative-position attribute must like 'relative-position:\"left top right bottom\"'");
} else {
System.err.println(
"relative-position attribute must like 'relative-position:\"left top right bottom\"'");
}
}
}
String fixedPosition = attrs.get("fixed-position");
if (fixedPosition != null && !"".equals(fixedPosition)) {
final String[] split = fixedPosition.split(" ");
if (split.length == 2) {
try {
float left = Float.parseFloat(split[0]);
float bottom = Float.parseFloat(split[1]);
para.setFixedPosition(left, bottom, UnitValue.createPercentValue(100));
} catch (Exception ex) {
if (log.isErrorEnabled()) {
log.error("fixed-position attribute must has a float value", ex);
} else {
System.err.println(
"fixed-position attribute must has a float value");
}
}
} else {
if (log.isErrorEnabled()) {
log.error("fixed-position attribute must like 'fixed-position:\"left bottom\"'");
} else {
System.err.println(
"fixed-position attribute must like 'fixed-position:\"left bottom\"'");
}
}
}
// 行间距
final String lineHeight = attrs.get("line-height");
if (null != lineHeight && !"".equals(lineHeight)) {
try {
para.setMultipliedLeading(Float.parseFloat(lineHeight));
} catch (NumberFormatException ex) {
if (log.isErrorEnabled()) {
log.error("line-height attribute must has a float value", ex);
} else {
System.err.println(
"line-height attribute must has a float value");
}
}
}
}
}
/**
* 添加一段文字到 PDF 文档
*
* @param blockType 块类型
* @param chunkList chunks 列表
* @param pdfBlockDefault
*/
private void addParagraph(BlockType blockType, List chunkList, PDFBlockDefault pdfBlockDefault) {
Paragraph para = new Paragraph();
for (TextChunk textChunk : chunkList) {
Text chunk = formatChunk(textChunk, pdfBlockDefault);
chunk.setSplitCharacters(splitCharacters);
para.add(chunk);
}
para.setMarginTop(pdfBlockDefault.lineSpaceBefore);
para.setMarginBottom(pdfBlockDefault.lineSpaceAfter);
para.setTextAlignment(pdfBlockDefault.alignment);
para.setFirstLineIndent(pdfBlockDefault.indent);
formatParagraph(para, chunkList);
document.add(para);
}
/**
* 添加一块内容到 PDF 文档,块可以为 Title、Section、等等,
* 参考类前面的数组定义
*
* @param blockName 块类型名,例如 title, section 等等
* @param chunkList 本块的内容,一个块包含多个 chunk,它们通过列表保存
*/
@Override
public void writeBlock(String blockName, List chunkList) {
if (blockName == null ||
chunkList == null || chunkList.size() == 0) {
return;
}
if (pdfDocument == null || pdfDocument.isClosed()) {
System.err.println("Document unopen yet, please open it first.");
return;
}
// 将块名称映射到内部的整数表示
final String lowerBlockName = blockName.toLowerCase();
if (!blockTypes.containsKey(lowerBlockName)) {
System.err.println("Block type '" + blockName + "' unknown!");
return;
}
BlockType blockType = blockTypes.get(lowerBlockName);
for (PDFBlockDefault pdfBlockDefault : pdfBlockDefaults) {
if (pdfBlockDefault.blockType == blockType) {
addParagraph(blockType, chunkList, pdfBlockDefault);
break;
}
}
}
/**
* 换页
*/
@Override
public void newPage() {
if (pdfDocument == null || pdfDocument.isClosed()) {
System.err.println("Document unopen yet, please open it first.");
return;
}
pdfDocument.addNewPage();
}
@Override
public void addHrule(Attributes attrs) {
try {
int width = 1;
int percent = 100;
String value = attrs.getValue("width");
if (value != null) {
try {
width = Integer.parseInt(value);
} catch (Exception ignored) {
}
}
value = attrs.getValue("percent");
if (value != null) {
try {
percent = Integer.parseInt(value);
} catch (Exception ignored) {
}
}
document.add(new AreaBreak());
document.add(new LineSeparator(new CustomLineSeparator(width, percent)));
} catch (Exception ex) {
ex.printStackTrace();
}
}
/**
* 添加一个图片
*
* @param attrs 属性
*/
@Override
public void addImage(Attributes attrs) {
try {
String src = attrs.getValue("src");
if (src == null) {
System.err.println("img missing src attribute.");
return;
}
Image img = images.get(src);
if (img == null) {
img = new Image(ImageDataFactory.create(src));
images.put(src, img);
}
document.add(img);
} catch (Exception e) {
e.printStackTrace();
}
}
private Table createTable(Map attrs) {
float width = 100;
float[] columns = null;
Table table;
String value = attrs.get("columns");
if (value != null) {
try {
String[] array = value.split(",");
columns = new float[array.length];
for (int i = 0; i < array.length; i++) {
columns[i] = Integer.parseInt(array[i]);
}
} catch (Exception ex) {
System.err.println("column must has a integer value");
}
}
if (columns == null) {
table = new Table(UnitValue.createPercentArray(1));
} else {
table = new Table(UnitValue.createPercentArray(columns));
}
value = attrs.get("width");
if (value != null) {
try {
width = Float.parseFloat(value);
} catch (Exception ex) {
System.err.println("width must has a float value");
}
}
table.setWidth(UnitValue.createPercentValue(width));
table.setFixedLayout();
// 外补丁
final String margin = attrs.get("margin");
if (margin != null) {
final String[] split = margin.split(" ");
try {
if (split.length == 1) {
table.setMargin(Float.parseFloat(margin));
} else if (split.length == 2) {
float top = Float.parseFloat(split[0]), bottom = Float.parseFloat(split[0]);
float left = Float.parseFloat(split[1]), right = Float.parseFloat(split[1]);
table.setMargins(top, right, bottom, left);
}
if (split.length == 4) {
float top = Float.parseFloat(split[0]);
float right = Float.parseFloat(split[1]);
float bottom = Float.parseFloat(split[2]);
float left = Float.parseFloat(split[3]);
table.setMargins(top, right, bottom, left);
}
} catch (Exception ex) {
if (log.isErrorEnabled()) {
log.error("margin attribute must has a float value", ex);
} else {
System.err.println(
"margin attribute must has a float value");
}
}
}
return table;
}
private Cell createTableCell(TextChunk textChunk,
PDFBlockDefault blockDefault) {
Map attrs = textChunk.getAttrs();
Text chunk = formatChunk(textChunk, blockDefault);
Paragraph phrase = new Paragraph();
// 行间距
final String lineHeight = attrs.get("line-height");
if (null != lineHeight && !"".equals(lineHeight)) {
try {
phrase.setMultipliedLeading(Float.parseFloat(lineHeight));
} catch (NumberFormatException ex) {
if (log.isErrorEnabled()) {
log.error("line-height attribute must has a float value", ex);
} else {
System.err.println(
"line-height attribute must has a float value");
}
}
}
phrase.add(chunk);
String value = attrs.get("colspan");
int colspan = 1;
if (value != null) {
try {
colspan = Integer.parseInt(value);
} catch (Exception ex) {
System.err.println("colspan must has a integer value");
}
}
Cell cell = new Cell(1, colspan);
cell.add(phrase);
cell.setVerticalAlignment(VerticalAlignment.MIDDLE);
value = attrs.get("align");
if (value != null) {
if ("left".equalsIgnoreCase(value)) {
cell.setTextAlignment(TextAlignment.LEFT);
} else if ("center".equalsIgnoreCase(value)) {
cell.setTextAlignment(TextAlignment.CENTER);
} else if ("right".equalsIgnoreCase(value)) {
cell.setTextAlignment(TextAlignment.RIGHT);
}
}
// 内补丁
final String padding = attrs.get("padding");
if (padding != null) {
final String[] split = padding.split(" ");
try {
if (split.length == 1) {
cell.setPadding(Float.parseFloat(padding));
} else if (split.length == 2) {
float top = Float.parseFloat(split[0]), bottom = Float.parseFloat(split[0]);
float left = Float.parseFloat(split[1]), right = Float.parseFloat(split[1]);
cell.setPaddings(top, right, bottom, left);
}
if (split.length == 4) {
float top = Float.parseFloat(split[0]);
float right = Float.parseFloat(split[1]);
float bottom = Float.parseFloat(split[2]);
float left = Float.parseFloat(split[3]);
cell.setPaddings(top, right, bottom, left);
}
} catch (Exception ex) {
if (log.isErrorEnabled()) {
log.error("padding attribute must has a float value", ex);
} else {
System.err.println(
"padding attribute must has a float value");
}
}
}
final String backgroundColor = attrs.get("background-color");
if (backgroundColor != null) {
final String[] colors = backgroundColor.split(" ");
if (colors.length == 3) {
try {
final int r = Integer.parseInt(colors[0]);
final int g = Integer.parseInt(colors[1]);
final int b = Integer.parseInt(colors[2]);
cell.setBackgroundColor(new DeviceRgb(r, g, b));
} catch (Exception ex) {
log.error("background-color item must has a float value", ex);
}
}
}
final String border = attrs.getOrDefault("border", "");
if (!"".equals(border)) {
if ("no-border".equals(border)) {
cell.setBorder(Border.NO_BORDER);
}
}
return cell;
}
@Override
public void writeTable(TextTable table) {
if (!isOpen() || table == null) {
return;
}
PDFBlockDefault blockDefault = null;
for (PDFBlockDefault def : this.pdfBlockDefaults) {
if (def.blockType == BlockType.BLOCK_PARA) {
blockDefault = def;
break;
}
}
Table pdfTable = createTable(table.getAttrs());
for (TextChunk textChunk : table.getCells()) {
pdfTable.addCell(createTableCell(textChunk, blockDefault));
}
document.add(pdfTable);
}
}
/**
* 一个类用于保存块默认属性
*/
class PDFBlockDefault {
protected BlockType blockType;
protected String fontFamily;
protected int fontSize;
protected FontStyle fontStyle;
protected TextAlignment alignment;
protected float indent;
protected float lineSpaceBefore;
protected float lineSpaceAfter;
public PDFBlockDefault(BlockType blockType, String family,
int size, FontStyle style, TextAlignment alignment, float indent,
float lineSpaceBefore, float lineSpaceAfter) {
this.blockType = blockType;
this.fontFamily = family;
this.fontSize = size;
this.fontStyle = style;
this.alignment = alignment;
this.indent = indent;
this.lineSpaceBefore = lineSpaceBefore;
this.lineSpaceAfter = lineSpaceAfter;
}
}
/**
* 块类型
*/
enum BlockType {
/**
* 标题
*/
BLOCK_TITLE(1),
/**
*
*/
BLOCK_CHAPTER(2),
/**
*
*/
BLOCK_SECTION(3),
/**
*
*/
BLOCK_PARA(3),
;
BlockType(int type) {
this.type = type;
}
private final int type;
public int getType() {
return type;
}
}
enum FontStyle {
/**
* 空
*/
NONE(0),
/**
* 加粗
*/
BOLD(1),
/**
* 下划线
*/
UNDERLINE(2),
ITALIC(4),
;
FontStyle(int type) {
this.type = type;
}
private final int type;
public int getType() {
return type;
}
}