需求:将Excel转化为PDF,支持图片,只单个sheet
要求:1、开源免费;2、支持跨平台
设计:1. 采用POI读取Excel文件;2. 采用itext生成PDF文件。
注:如果费用许可的情况下,建议使用Aspose(可跨平台,收费,不开源)。
开发难点:
1. 将POI标准转化为Itext标准,包括单元格内容,字体,样式,单元格的合并等;
2. Excel文件x轴可以滚动,而PDF文件宽度是固定的,转化后的PDF内容可能会出现挤压的情况。
思路:1. 先将poi对转化为标准对象,如将POI的颜色转化为RGB;2. 将标准对象转化为itext对象。
转换事项:
1. 单元格类型:常规、数值、文本等。
2. 对齐方式:水平对齐只支持左对齐、居中、右对齐,默认左对齐;垂直对齐方式只顶端对齐、垂直居中、底端对齐,默认底端对齐。
3. 文本的字体(暂不支持,目前固定为STSong-Light)、颜色(支持)、大小(支持)、是否加粗(支持),是否倾斜(支持),是否有下划线(支持),是否自动换行(支持)
4. 框线:下框线、上框线、左框线、右框线(仅设置边框颜色和边框宽度)
5. 填充色(背景色):支持。
6. 单元格的高度和宽度
遗留问题(后续改善):
1. excel不支持黑色背景。
2. excel相邻单元格都有边框时,PDF文件边框变粗。
3. 当excel单元格处在图片区域,PDF中该单元格无文本。
4. 当excel文件存在多张图片有重合区域时,PDF只有其中的一张图片(起始单元格最靠前的图片)。
5. excel单元格字体加粗、倾斜、下划线,pdf只有加粗、下划线,缺少倾斜。
6. 部分情况pdf样式失真。
7.目前该文主要是验证excel转pdf,后期会更新优化后方案。
示例(excel2003文件转化为pdf)
excel2003文件:
转化后的PDF文件:
测试代码:
// poi和itext将Excel转化为PDF(支持图片)
String pdf = "F:/Users/zyj/Desktop/2019-09-27 自由报表/插件测试/excel2pdf_new.pdf";
Xls2Pdf xls2Pdf = new Xls2Pdf(xls, 0);
xls2Pdf.savePdf(pdf);
poi读取xls文件,生成PDF的代码:
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.Map;
import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFPictureData;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.util.CellRangeAddress;
import com.itextpdf.text.BadElementException;
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Image;
import com.itextpdf.text.Phrase;
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.pdf.PdfPCell;
import com.itextpdf.text.pdf.PdfPTable;
import com.itextpdf.text.pdf.PdfWriter;
/**
* Excel2003文件转化为PDF文件
*
* @author zyj
* @date 2019-10-18
*/
public class Xls2Pdf {
private HSSFWorkbook _wb = null;
private int _sheetIndex = 0;
private HSSFSheet _sheet = null;
// 文本中的合并单元格
private List<CellRangeAddress> _ranges = null;
// 单个Sheet中所有的图片信息
private Map<String, HSSFPictureData> _pics = null;
// 图片中的最后一个单元格位置
private Integer[] _lastCell = null;
/**
* 构造函数
*
* @param excel excel2003文件的全路径
* @param sheetindex sheet索引
* @throws IOException
*/
public Xls2Pdf(String excel, int sheetIndex) throws IOException {
InputStream input = new FileInputStream(excel);
HSSFWorkbook wb = new HSSFWorkbook(input);
this._wb = wb;
this._sheetIndex = sheetIndex;
}
/**
* 构造函数
*
* @param wb excel工作薄
* @param sheetIndex sheet索引
*/
public Xls2Pdf(HSSFWorkbook wb, int sheetIndex) {
this._wb = wb;
this._sheetIndex = sheetIndex;
}
/**
* 保存为pdf文件
*
* @param pdf pdf文件的全路径
* @throws IOException
* @throws BadElementException
* @throws DocumentException
*/
public void savePdf(String pdf) throws IOException, BadElementException, DocumentException {
PdfPTable table = this.genPdfPTable();
// Step 1 — Create a Document
Document document = new Document();
// Step 2 — Get a PdfWriter instance
FileOutputStream output = new FileOutputStream(pdf);
PdfWriter.getInstance(document, output);
// Step 3 — Open the Document
document.open();
// Step 4 — Add content.
document.add(table);
// Step 5 — Close the Document
document.close();
}
/**
* 将sheet转化为PdfPTable
*
* @return PdfPTable对象
* @throws IOException
* @throws BadElementException
* @throws DocumentException
*/
public PdfPTable genPdfPTable() throws IOException, BadElementException, DocumentException {
if (this._wb == null) {
return null;
}
this._sheet = this._wb.getSheetAt(this._sheetIndex);
if (this._sheet == null) {
return null;
}
// 文本中的合并单元格
this._ranges = this._sheet.getMergedRegions();
// sheet中所有图片信息
this._pics = XlsHelper.getPictrues(this._wb, this._sheetIndex