需求:根据数据信息生成PDF文档(文档包含文本数据——中文、包含复选框、包含签字图片和表格布局),然后将所生成的PDF文档转化为图片显示。
(注:由于表格的确定性,且长时间不需要修改,故表格原本内容均为固定填写)
1.使用iText生成PDF文件
引入iText依赖
<!-- 引入iText依赖 -->
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itextpdf</artifactId>
<version>5.0.6</version>
</dependency>
使用Document生成PDF文件,普通文字使用Paragraph直接添加,但需要注意汉字无法显示的问题需要使用外部引入的字体文件。
添加表格则需要使用PdfPTable,可以自行封装一个方法。
public static void createPDF(String filePath, formInfoApiModel formInfoApiModel)throws Exception{
//设置pdf纸张大小
Document document = new Document(PageSize.A4);
try {
//设置字体(/simsun.ttf,引入项目中的字体文件,解决汉字无法显示的问题)
Font font = new Font(BaseFont.createFont( "/simsun.ttf",BaseFont.IDENTITY_H,BaseFont.NOT_EMBEDDED),18);
PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(filePath));
/**
* pdf内容
*/
document.open();
//标题(整个文件标题)——文字部分
font = new Font(BaseFont.createFont( "/simsun.ttf",BaseFont.IDENTITY_H,BaseFont.NOT_EMBEDDED),10);
Chunk Chunk = new Chunk(" 抽样单编号: ", font);
document.add(Chunk);
//添加编号并生成下划线
Chunk = new Chunk(formInfoApiModel.getGbTblFormInfo().getFormNumber(),font);
Chunk.setUnderline(BaseColor.BLACK,0.1f,-2f,-25f,2,2);
document.add(Chunk);
//标题——表格部分
PdfPTable table = createTableTitle(writer,formInfoApiModel);
document.add(table);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (DocumentException e) {
e.printStackTrace();
} catch (IOException e){
e.printStackTrace();
} finally{
document.close();
}
}
2.使用PdfPTable和PdfPCell生成数据表格
使用PdfPTable生成数据表格,根据实际生成文件表格形式设计数据表格。使用PdfPCell生成表格的单元格,用于拼接数据表格。
/**
* @Method createTableTitle
* @Author zhanglin
* @Version 1.0
* @Description 生成表格标题部分内容
* @param writer
* @Return com.itextpdf.text.pdf.PdfPTable
* @Exception
* @Date 2019-11-26 8:53
*/
public static PdfPTable createTableTitle(PdfWriter writer,formInfoApiModel formInfoApiModel) throws DocumentException,IOException{
//formInfoApiModel为项目实际数据类型
//设定任务字体(解决汉字显示内容)
Font font = new Font(BaseFont.createFont( "/simsun.ttf",BaseFont.IDENTITY_H,BaseFont.NOT_EMBEDDED),10);
//设定生成表格的规格
float widthArray[] = {130,250,80,72,48};
//createPdfPTable为自行封装方法,见下。
PdfPTable table = createPdfPTable(5,widthArray);//生成一个两列的表格
//设置单元格高度常量
int size = 20;
//createPdfPCell为自行封装方法,见下。
//添加提示信息为“任务来源”的单元格
table.addCell(createPdfPCell(size,"任务来源",font,0,0,1,1,
false,false,false,false));
//填充任务来源的实际数据
table.addCell(createPdfPCell(size,formInfoApiModel.getGbTblFormInfo().getFormMissionsource(),font,0,0,1,1,
false,false,false,false));
//添加提示信息为“任务类别”的单元格
table.addCell(createPdfPCell(size,"任务类别",font,0,0,1,1,false,false,false,false));
/**
* 添加附带复选框的任务类别的数据
*/
//createCheckbox为自行封装方法,见下。
//checkDictionaryInfo为自行封装方法,见下。
//监督抽检
table.addCell(createCheckbox(size,"监督抽查",4,"1",
checkDictionaryInfo(formInfoApiModel.getGbTblFormInfo().getFormMissiontype(),"监督抽查"),font,0,0,false,true,false,false));
//风险监测
table.addCell(createCheckbox(size,"风险监测",4,"1",
checkDictionaryInfo(formInfoApiModel.getGbTblFormInfo().getFormMissiontype(),"监督抽检"),font,0,0,false,false,false,true));
//返回填充好的数据表格
return table;
}
定义createPdfPTable方法,生成表格对象。
/**
* @Method createPdfPTable
* @Author zhanglin
* @Version 1.0
* @Description 生成表格
* @param columnSize
* @param widthArray
* @Return com.itextpdf.text.pdf.PdfPTable
* @Exception
* @Date 2019-11-28 14:31
*/
public static PdfPTable createPdfPTable(int columnSize,float widthArray[])throws DocumentException{
//根据传输的数字和数组,确定需要生成表格的列数和每列的宽度
PdfPTable table = new PdfPTable(columnSize);//生成一个多列列的表格
table.setTotalWidth(widthArray);//设置表格的各列宽度
table.setLockedWidth(true);//锁定每列的宽度
//返回生成好的表格对象
return table;
}
定义createPdfPCell方法,生成表格单元格,填充数据表格。
/**
* @Method createPdfPCell
* @Author zhanglin
* @Version 1.0
* @Description 生成表格元素
* @param cellSize
* @param cellText
* @param font
* @param colSpan
* @param rowSpan
* @param center
* @param middle
* @param top
* @param right
* @param bottom
* @param left
* @Return com.itextpdf.text.pdf.PdfPCell
* @Exception
* @Date 2019-11-28 14:10
*/
public static PdfPCell createPdfPCell(int cellSize,String cellText,Font font,int colSpan,int rowSpan,
int center,int middle,boolean top,boolean right,boolean bottom,boolean left){
//判断字符串是否为空
if(cellText == null){
cellText = "";
}
//Phrase设置其显示内容
PdfPCell pdfPCell = new PdfPCell(new Phrase(cellText,font));
pdfPCell.setFixedHeight(cellSize);//设置单元格固定高度
//判断显示信息的水平对齐方式
if(center == 0){
pdfPCell.setHorizontalAlignment(Element.ALIGN_LEFT);//水平居左
}else if(center == 1){
pdfPCell.setHorizontalAlignment(Element.ALIGN_CENTER);//水平居中
}else {
pdfPCell.setHorizontalAlignment(Element.ALIGN_RIGHT);//水平居右
}
//判断显示信息的垂直对齐方式
if(middle == 0){
pdfPCell.setVerticalAlignment(Element.ALIGN_TOP);//垂直居中
}else if(middle == 1){
pdfPCell.setVerticalAlignment(Element.ALIGN_MIDDLE);//水平居中
}else {
pdfPCell.setVerticalAlignment(Element.ALIGN_BOTTOM);//水平居右
}
//判断单元格的表格宽度
if(bottom){
pdfPCell.setBorderWidthBottom(0);
}
if(left){
pdfPCell.setBorderWidthLeft(0);
}
pdfPCell.setFixedHeight(cellSize);
if(top){
pdfPCell.setBorderWidthTop(0);
}
if(right){
pdfPCell.setBorderWidthRight(0);
}
if(colSpan != 0){
pdfPCell.setColspan(colSpan);
}
if(rowSpan != 0){
pdfPCell.setRowspan(rowSpan);
}
return pdfPCell;
}
定义createCheckbox方法,生成表格单元格,填充数据表格。
/**
* @Method createCheckbox
* @Author zhanglin
* @Version 1.0
* @Description 生成带复选框的表格元素
* @param cellSize
* @param cellText
* @param textSize
* @param checkName
* @param isCheck
* @param font
* @param colSpan
* @param rowSpan
* @param top
* @param right
* @param bottom
* @param left
* @Return com.itextpdf.text.pdf.PdfPCell
* @Exception
* @Date 2019-11-27 10:04
*/
public static PdfPCell createCheckbox(int cellSize,String cellText,int textSize,String checkName,boolean isCheck,
Font font,int colSpan,int rowSpan,boolean top,boolean right,boolean bottom,boolean left){
PdfPCell pdfPCell;
pdfPCell = new PdfPCell(new Phrase(cellText,font));
//定义CheckboxCellEvent方法,画出复选框形式
pdfPCell.setCellEvent(new CheckboxCellEvent(checkName,isCheck,textSize));
//设置单元格固定高度
pdfPCell.setFixedHeight(cellSize);
//设置单元格表格宽度
if(top){
pdfPCell.setBorderWidthTop(0);
}
if(right){
pdfPCell.setBorderWidthRight(0);
}
if(bottom){
pdfPCell.setBorderWidthBottom(0);
}
if(left){
pdfPCell.setBorderWidthLeft(0);
}
//设置单元格是否需要合并行或者合并列
if(rowSpan != 0){
pdfPCell.setRowspan(rowSpan);
}
if(colSpan != 0){
pdfPCell.setColspan(colSpan);
}
pdfPCell.setHorizontalAlignment(Element.ALIGN_CENTER);//水平居中
pdfPCell.setVerticalAlignment(Element.ALIGN_MIDDLE);//垂直居中
return pdfPCell;
}
定义CheckboxCellEvent方法,自行画出复选框形式。
/**
* @ProjectName: quality
* @Package: com.xwkj.quality.utils
* @ClassName: CheckboxCellEvent
* @Author: zhanglin
* @Description: 生成复选框工具类
* @Date: 2019-11-26 9:20
* @Version: 1.0
*/
public class CheckboxCellEvent implements PdfPCellEvent {
protected String name;//变量名称
protected boolean flag ;//是否选中
protected int size;//名称字符长度(便于定位)
public CheckboxCellEvent(String name, boolean flag,int size) {
this.name = name;
this.flag = flag;
this.size = size;
}
// 根据变量名称、选中状态、字符长度生成定位好的复选框
public void cellLayout(PdfPCell cell, Rectangle position,PdfContentByte[] canvases) {
PdfWriter writer = canvases[0].getPdfWriter();
//判断定位位置
float x = (position.getLeft() + position.getRight()) / 2;
float y = (position.getTop() + position.getBottom()) / 2;
// define the position of a check box that measures 20 by 20
//画勾
Rectangle rect;
rect = new Rectangle(x - 54, y - 6, x + 2, y + 3);
RadioCheckField checkbox = new RadioCheckField(writer, rect, name, "On");
checkbox.setCheckType(RadioCheckField.TYPE_CHECK);
//判断复选框的选中状态
if(flag){
//设置为选中状态
checkbox.setChecked(true);
}
else{
checkbox.setChecked(false);
}
//画框
PdfContentByte canvas = canvases[PdfPTable.LINECANVAS];
canvas.setColorStroke(BaseColor.BLACK);
canvas.setLineDash(1f);
canvas.rectangle(x - 30, y - 5, 8,8);
canvas.stroke();
try {
writer.addAnnotation(checkbox.getCheckField());
} catch (Exception e) {
throw new ExceptionConverter(e);
}
}
}
定义checkDictionaryInfo方法,确定复选框的选中状态。
/**
* @Method checkDictionaryInfo
* @Author zhanglin
* @Version 1.0
* @Description 判断变量字符串中是否包含某一变量
* @param checkByString
* @param checkString
* @Return boolean
* @Exception
* @Date 2019-12-04 13:36
*/
public static boolean checkDictionaryInfo(String checkByString,String checkString){
//判断所传变量是否为空
if(checkByString == null){
checkByString = "";
}
//判断所传变量中是否含有表格数据规定的变量,即是否选中
if(checkByString.contains(checkString)){
return true;
}else{
return false;
}
}
3.向PdfPCell单元格中插入图片
使用Image根据图片路径获取图片,插入到单元格内。(图片由base64格式变量转换而来,使用
createImageBase64自定义方法)
PdfPCell pdfPCell;
//判断是否生成签字图片
String signCheck = createImageByBase64.createImageBase64(formInfoApiModel.getGbTblFormInfo().getFormSignaturecheck(),
formInfoApiModel.getGbTblFormInfo().getFormNumber(),"Check");
if(signCheck != null){
//生成后,插入图片
Image image = Image.getInstance(signCheck);
//设置图片显示的比例大小
image.scalePercent(12f);
//添加图片
pdfPCell = new PdfPCell(image);
}else{
//未生成
pdfPCell = new PdfPCell();
}
4.使用Base64格式变量转换为图片
定义createImageBase64方法,转换图片。
public static String createImageBase64(String sign,String nameNum,String name) throws Exception {
//传输项目数据
String fileNewName = nameNum + name + ".png";
//设置存储路径
String fileAdd = dateUtils.formatDateByFormat(new Date(), "yyyyMMdd");
String filePath = "d://quaUpload/pdf/" + fileAdd + "/" + nameNum + "/" + fileNewName;
// 签名数据为空数据为空
if(sign == null){
return null;
}else{
String signStr = sign.split(",")[1];
//将签名转换为图片
BASE64Decoder decoder = new BASE64Decoder();
OutputStream out = null;
try {
out = new FileOutputStream(filePath);
// Base64解码
byte[] b = decoder.decodeBuffer(signStr);
for (int i = 0; i < b.length; ++i) {
if (b[i] < 0) {// 调整异常数据
b[i] += 256;
}
}
out.write(b);
}catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
out.flush();
out.close();
return filePath;
}
}
}
5.将Pdf文件转换为图片
使用pdfbox插件将pdf插件转化为图片,引入依赖
<!-- https://mvnrepository.com/artifact/org.apache.pdfbox/pdfbox -->
<dependency>
<groupId>org.apache.pdfbox</groupId>
<artifactId>pdfbox</artifactId>
<version>2.0.12</version>
</dependency>
定义createImage方法,转换图片。(pdf生成转换图片存在两种方法:1.使用 icepdf 2. 使用pdfbox 实现代码基本一致,但是用icepdf转化图片是,有图形 绘画出的复选框中的对勾会转化失败,但是用pdfbox就可以成功转化。)
public static String createImage(String filePath,String nameNum) throws Exception{
String picUrl = null;
File file = new File(filePath);
try {
//设置存储路径
String path = "d://quaUpload/pdf/";
String fileAdd = dateUtils.formatDateByFormat(new Date(), "yyyyMMdd");
//文件路径
String filePathImg = path + "/" + fileAdd + "/" + nameNum + "/" + nameNum + ".png";
//读取文件路径
picUrl = "http://xiangwangkeji.imwork.net/upload/pdf/"+ fileAdd + "/" + nameNum + "/" + nameNum + ".png";
//读取pdf文件
PDDocument doc = PDDocument.load(file);
PDFRenderer renderer = new PDFRenderer(doc);
int pageCount = doc.getNumberOfPages();
for(int i=0; i<pageCount; i++){
// 方式1,第二个参数是设置缩放比(即像素)
// BufferedImage image = renderer.renderImageWithDPI(i, 296);
// 方式2,第二个参数是设置缩放比(即像素)
BufferedImage image = renderer.renderImage(i, 1f); //第二个参数越大生成图片分辨率越高,转换时间也就越长
ImageIO.write(image, "PNG", new File(filePathImg));
}
} catch (IOException e) {
e.printStackTrace();
}
return picUrl;
}
生成图片
文档图片