feature1:支持excel转换为PDF

This commit is contained in:
jipengfei-jpf 2024-12-02 17:32:07 +08:00
parent d686f6171a
commit 587971c921
70 changed files with 995 additions and 5 deletions

BIN
doc/font/SimHei.ttf Normal file

Binary file not shown.

View File

@ -16,6 +16,10 @@
<name>fastexcel-core</name>
<version>${revision}</version>
<properties>
<itext.version>7.1.15</itext.version>
</properties>
<dependencies>
<dependency>
<groupId>org.apache.commons</groupId>
@ -61,5 +65,47 @@
<artifactId>fastexcel-support</artifactId>
<version>0.0.1</version>
</dependency>
<!-- itext7 -->
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itext7-core</artifactId>
<version>${itext.version}</version>
<type>pom</type>
</dependency>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>kernel</artifactId>
<version>${itext.version}</version>
</dependency>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>io</artifactId>
<version>${itext.version}</version>
</dependency>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>layout</artifactId>
<version>${itext.version}</version>
</dependency>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>forms</artifactId>
<version>${itext.version}</version>
</dependency>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>pdfa</artifactId>
<version>${itext.version}</version>
</dependency>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>pdftest</artifactId>
<version>${itext.version}</version>
</dependency>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>font-asian</artifactId>
<version>${itext.version}</version>
</dependency>
</dependencies>
</project>

View File

@ -1,5 +1,10 @@
package cn.idev.excel;
import cn.idev.excel.fileconvertor.ExcelConverter;
import cn.idev.excel.fileconvertor.FileConverterContext;
import java.io.File;
/**
* This is actually {@link FastExcelFactory}, and short names look better.
*
@ -7,4 +12,18 @@ package cn.idev.excel;
*/
public class FastExcel extends FastExcelFactory {
/**
* Convert excel to pdf
*
* @param excelFile excel file
* @param pdfFile pdf file
* @param fontPath font path for pdf can be null
* @param sheets sheet index to convert, if null convert all sheets
*/
public static void convertToPdf(File excelFile, File pdfFile, String fontPath, int[] sheets) {
FileConverterContext context = new FileConverterContext(excelFile, pdfFile, fontPath, sheets);
ExcelConverter excelConverter = context.getExcelConverter();
excelConverter.convertToPdf();
}
}

View File

@ -353,4 +353,25 @@ public class FastExcelFactory {
}
return excelReaderSheetBuilder;
}
/**
* Build excel the 'readSheet'
* @param sheetNo Index of sheet,0 base.
* @param sheetName The name of sheet.
* @param numRows The number of rows to read, the default is all, start with 0.
* @return
*/
public static ExcelReaderSheetBuilder readSheet(Integer sheetNo, String sheetName,Integer numRows) {
ExcelReaderSheetBuilder excelReaderSheetBuilder = new ExcelReaderSheetBuilder();
if (sheetNo != null) {
excelReaderSheetBuilder.sheetNo(sheetNo);
}
if (sheetName != null) {
excelReaderSheetBuilder.sheetName(sheetName);
}
if (numRows !=null) {
excelReaderSheetBuilder.numRows(numRows);
}
return excelReaderSheetBuilder;
}
}

View File

@ -0,0 +1,172 @@
package cn.idev.excel.fileconvertor;
import com.itextpdf.layout.element.Table;
import com.itextpdf.layout.property.TextAlignment;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import java.io.IOException;
import java.util.List;
public abstract class BaseExcelConverter implements ExcelConverter {
private final FileConverterContext context;
public BaseExcelConverter(FileConverterContext context) {
this.context = context;
}
@Override
public void convertToPdf() {
try {
for (int sheetIndex : context.getSheets()) {
processSheet(sheetIndex);
}
context.getDocument().close();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private void processSheet(int sheetIndex) throws IOException {
Sheet sheet = context.getWorkbook().getSheetAt(sheetIndex);
if (sheet == null || sheet.getRow(0) == null) {
return;
}
float[] columnWidths = getColumnWidths(sheet);
Table table = new Table(columnWidths);
addRowsToTable(table, sheet, columnWidths, context.getFountPath());
// addPicsToTable(table, sheet);
context.getDocument().add(table);
}
protected abstract void addPicsToTable(Table table, Sheet sheet);
private void addRowsToTable(Table table, Sheet sheet, float[] columnWidths, String fontPath) throws IOException {
int lastRowNum = sheet.getLastRowNum() + 1;
int lastCellNum = sheet.getRow(0).getLastCellNum();
for (int i = 0; i < lastRowNum; i++) {
Row row = sheet.getRow(i);
addRowToTable(table, row, lastCellNum, columnWidths, fontPath);
}
}
private void addRowToTable(Table table, Row row, int lastCellNum, float[] columnWidths, String fontPath) throws IOException {
if (row == null) {
addEmptyCells(table, lastCellNum); // 0 for empty row
return;
}
for (int j = 0; j < lastCellNum; j++) {
Cell cell = row.getCell(j);
if (cell != null && !isCellProcessed(cell)) {
// addCellToTable(table, cell, columnWidths, fontPath);
CellRangeAddress cellRange = getCellRangeAddress(cell);
int rowspan = (cellRange != null) ? (cellRange.getLastRow() - cellRange.getFirstRow() + 1) : 1;
int colspan = (cellRange != null) ? (cellRange.getLastColumn() - cellRange.getFirstColumn() + 1) : 1;
if ((cellRange != null)) {
j = cellRange.getLastColumn();
}
float maxWidth = (cellRange != null) ? calculateMaxWidth(columnWidths, cellRange) : columnWidths[j];
com.itextpdf.layout.element.Cell pdfCell = convertCell(cell, rowspan, colspan, maxWidth, fontPath);
table.addCell(pdfCell);
} else if (cell == null) {
addEmptyCell(table);
}
}
}
private float calculateMaxWidth(float[] columnWidths, CellRangeAddress cellRange) {
float maxWidth = 0;
for (int k = cellRange.getFirstColumn(); k < cellRange.getLastColumn(); k++) {
maxWidth += columnWidths[k];
}
return maxWidth;
}
private void addEmptyCell(Table table) {
com.itextpdf.layout.element.Cell pdfCell = new com.itextpdf.layout.element.Cell();
pdfCell.setBorder(com.itextpdf.layout.borders.Border.NO_BORDER);
table.addCell(pdfCell);
}
private void addEmptyCells(Table table, int numberOfCells) {
for (int j = 0; j < numberOfCells; j++) {
addEmptyCell(table);
}
}
protected abstract com.itextpdf.layout.element.Cell convertCell(Cell cell, int rowspan, int colspan, float maxWidth, String fontPath) throws IOException;
public static com.itextpdf.layout.property.VerticalAlignment getVerticalAlignment(VerticalAlignment verticalAlignment) {
switch (verticalAlignment) {
case TOP:
return com.itextpdf.layout.property.VerticalAlignment.TOP;
case BOTTOM:
return com.itextpdf.layout.property.VerticalAlignment.BOTTOM;
case JUSTIFY:
case CENTER:
return com.itextpdf.layout.property.VerticalAlignment.MIDDLE;
}
return com.itextpdf.layout.property.VerticalAlignment.MIDDLE;
}
public static TextAlignment getTextAlignment(org.apache.poi.ss.usermodel.HorizontalAlignment alignment, CellType cellType) {
switch (alignment) {
case LEFT:
return TextAlignment.LEFT;
case RIGHT:
return TextAlignment.RIGHT;
case CENTER:
return TextAlignment.CENTER;
case JUSTIFY:
return TextAlignment.JUSTIFIED;
case GENERAL:
if (cellType == CellType.NUMERIC) {
return TextAlignment.RIGHT;
} else if (cellType == CellType.BOOLEAN) {
return TextAlignment.CENTER;
}
}
return TextAlignment.LEFT;
}
private float[] getColumnWidths(Sheet sheet) {
short lastCellNum = sheet.getRow(0).getLastCellNum();
float[] widths = new float[lastCellNum];
for (int i = 0; i < lastCellNum; i++) {
widths[i] = sheet.getColumnWidthInPixels(i);
}
return widths;
}
private boolean isCellProcessed(Cell cell) {
List<CellRangeAddress> mergedRegions = cell.getSheet().getMergedRegions();
int rowIndex = cell.getRowIndex();
int columnIndex = cell.getColumnIndex();
for (CellRangeAddress cellAddresses : mergedRegions) {
if (cellAddresses.getFirstRow() <= rowIndex && cellAddresses.getLastRow() >= rowIndex
&& cellAddresses.getFirstColumn() <= columnIndex && cellAddresses.getLastColumn() >= columnIndex) {
return !(cellAddresses.getFirstRow() == rowIndex && cellAddresses.getFirstColumn() == columnIndex);
}
}
return false;
}
private CellRangeAddress getCellRangeAddress(Cell cell) {
List<CellRangeAddress> mergedRegions = cell.getSheet().getMergedRegions();
int rowIndex = cell.getRowIndex();
int columnIndex = cell.getColumnIndex();
for (CellRangeAddress cellAddresses : mergedRegions) {
if (cellAddresses.getFirstRow() == rowIndex && cellAddresses.getFirstColumn() == columnIndex) {
return cellAddresses;
}
}
return null;
}
}

View File

@ -0,0 +1,45 @@
package cn.idev.excel.fileconvertor;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.usermodel.DateUtil;
import org.apache.poi.util.LocaleUtil;
import java.text.SimpleDateFormat;
public class Excel2PdfUtils {
private static final String DATE_FORMAT = "yyyy-MM-dd HH:mm:ss"; // 日期格式
private static final String TRUE_STRING = "TRUE";
private static final String FALSE_STRING = "FALSE";
private static final String EMPTY_STRING = "";
// 使用单例模式确保 SimpleDateFormat 只被创建一次
private static final ThreadLocal<SimpleDateFormat> DATE_FORMATTER = ThreadLocal.withInitial(() ->
new SimpleDateFormat(DATE_FORMAT, LocaleUtil.getUserLocale())
);
public static String getValue(Cell cell) {
if (cell == null) {
return EMPTY_STRING;
}
CellType cellType = cell.getCellType();
switch (cellType) {
case BOOLEAN:
return cell.getBooleanCellValue() ? TRUE_STRING : FALSE_STRING;
case NUMERIC:
return getNumericCellValue(cell);
case STRING:
return cell.getStringCellValue();
default:
return EMPTY_STRING;
}
}
private static String getNumericCellValue(Cell cell) {
if (DateUtil.isCellDateFormatted(cell)) {
return DATE_FORMATTER.get().format(cell.getDateCellValue());
}
return String.valueOf(cell.getNumericCellValue());
}
}

View File

@ -0,0 +1,17 @@
package cn.idev.excel.fileconvertor;
import java.io.File;
/**
* Excel convert to other file
* @author jipengfei
*/
public interface ExcelConverter {
/**
* excel to pdf
*
*/
void convertToPdf();
}

View File

@ -0,0 +1,74 @@
package cn.idev.excel.fileconvertor;
import cn.idev.excel.read.metadata.ReadWorkbook;
import cn.idev.excel.support.ExcelTypeEnum;
import com.itextpdf.kernel.geom.PageSize;
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfWriter;
import com.itextpdf.layout.Document;
import lombok.Getter;
import lombok.Setter;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
@Getter
@Setter
public class FileConverterContext {
private File inputFile;
private File outputFile;
private String fountPath;
private Workbook workbook;
private Document document;
private int[] sheets;
private ExcelTypeEnum excelTypeEnum;
public FileConverterContext(File inputFile, File outputFile, String fountPath, int[] sheets) {
try {
this.inputFile = inputFile;
this.outputFile = outputFile;
this.fountPath = fountPath;
ReadWorkbook readWorkbook = new ReadWorkbook();
readWorkbook.setFile(inputFile);
excelTypeEnum = ExcelTypeEnum.valueOf(readWorkbook);
if (excelTypeEnum == ExcelTypeEnum.XLSX) {
this.workbook = new XSSFWorkbook(inputFile);
} else if (excelTypeEnum == ExcelTypeEnum.XLS) {
this.workbook = new HSSFWorkbook(new FileInputStream(inputFile));
} else {
throw new IllegalArgumentException("Not supported excel type");
}
PdfDocument pdfDocument = new PdfDocument(new PdfWriter(outputFile));
this.document = new Document(pdfDocument, PageSize.A4.rotate());
if (sheets == null) {
this.sheets = new int[workbook.getNumberOfSheets()];
for (int i = 0; i < workbook.getNumberOfSheets(); i++) {
this.sheets[i] = i;
}
} else {
this.sheets = sheets;
}
} catch (IOException e) {
throw new RuntimeException(e);
} catch (InvalidFormatException e) {
throw new RuntimeException(e);
}
}
public ExcelConverter getExcelConverter() {
if (excelTypeEnum == ExcelTypeEnum.XLSX) {
return new cn.idev.excel.fileconvertor.v07.XlsxConverter(this);
} else if (excelTypeEnum == ExcelTypeEnum.XLS) {
return new cn.idev.excel.fileconvertor.v03.XlsConverter(this);
}
throw new IllegalArgumentException("Not supported excel type");
}
}

View File

@ -0,0 +1,150 @@
package cn.idev.excel.fileconvertor.v03;
import cn.idev.excel.fileconvertor.BaseExcelConverter;
import cn.idev.excel.fileconvertor.Excel2PdfUtils;
import cn.idev.excel.fileconvertor.FileConverterContext;
import cn.idev.excel.util.StringUtils;
import com.itextpdf.io.font.PdfEncodings;
import com.itextpdf.kernel.colors.Color;
import com.itextpdf.kernel.colors.ColorConstants;
import com.itextpdf.kernel.colors.DeviceRgb;
import com.itextpdf.kernel.font.PdfFontFactory;
import com.itextpdf.layout.borders.*;
import com.itextpdf.layout.element.*;
import com.itextpdf.layout.element.Cell;
import com.itextpdf.layout.element.Table;
import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.hssf.util.HSSFColor;
import org.apache.poi.ss.usermodel.*;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
public class XlsConverter extends BaseExcelConverter {
public XlsConverter(FileConverterContext context) {
super(context);
}
@Override
public void addPicsToTable(Table table, Sheet sheet) {
HSSFPatriarch drawingPatriarch = ((HSSFSheet) sheet).getDrawingPatriarch();
if (drawingPatriarch != null) {
List<HSSFPicture> pictures = new ArrayList<>();
for (HSSFShape shape : drawingPatriarch.getChildren()) {
if (shape instanceof HSSFPicture) {
pictures.add((HSSFPicture) shape);
}
}
table.setNextRenderer(new XlsImageTableRenderer(table, pictures, (HSSFSheet) sheet));
}
}
@Override
public Cell convertCell(org.apache.poi.ss.usermodel.Cell cell, int rowspan, int colspan, float maxWidth, String fontPath) throws IOException {
String value = Excel2PdfUtils.getValue(cell);
Cell pdfCell = createPdfCell(rowspan, colspan, cell, value, maxWidth, fontPath);
return pdfCell;
}
private Cell createPdfCell(int rowspan, int colspan, org.apache.poi.ss.usermodel.Cell cell, String value, float maxWidth, String fontPath) throws IOException {
float cellHeight = cell.getRow().getHeightInPoints() * 1.2f;
Cell pdfCell = new Cell(rowspan, colspan)
.setHeight(cellHeight)
.setPadding(0);
Text text = new Text(value);
setPdfCellFont((HSSFCell) cell, text, fontPath);
Paragraph paragraph = new Paragraph(text).setPadding(0f).setMargin(0f);
HSSFCellStyle cellStyle = ((HSSFCell) cell).getCellStyle();
if (cellStyle.getWrapText()) {
paragraph.setMaxWidth(maxWidth);
}
pdfCell.add(paragraph);
setCellStyles(cell, pdfCell);
return pdfCell;
}
private void setCellStyles(org.apache.poi.ss.usermodel.Cell cell, Cell pdfCell) throws IOException {
HSSFCellStyle cellStyle = ((HSSFCell) cell).getCellStyle();
// Layout
pdfCell.setVerticalAlignment(getVerticalAlignment(cellStyle.getVerticalAlignment()));
pdfCell.setTextAlignment(getTextAlignment(cellStyle.getAlignment(), cell.getCellType()));
// Set borders
transformBorders((HSSFCell) cell, pdfCell);
// Set background color
setBackgroundColor(cellStyle, pdfCell, cell);
}
private void setBackgroundColor(HSSFCellStyle cellStyle, Cell pdfCell, org.apache.poi.ss.usermodel.Cell cell) {
short colorIndex = cellStyle.getFillForegroundColor();
HSSFWorkbook workbook = (HSSFWorkbook) cell.getSheet().getWorkbook();
HSSFColor color = workbook.getCustomPalette().getColor(colorIndex);
if (color != null && color.getIndex() != 64) {
short[] triplet = color.getTriplet();
int r = Math.min(triplet[0] + 32, 255);
int g = Math.min(triplet[1] + 90, 255);
int b = Math.min(triplet[2] + 60, 255);
pdfCell.setBackgroundColor(new DeviceRgb(r, g, b));
}
}
public static void transformBorders(HSSFCell cell, Cell pdfCell) {
HSSFCellStyle cellStyle = cell.getCellStyle();
pdfCell.setBorderBottom(getBorder(cellStyle.getBorderBottom(), cellStyle.getBottomBorderColor(), cell));
pdfCell.setBorderLeft(getBorder(cellStyle.getBorderLeft(), cellStyle.getLeftBorderColor(), cell));
pdfCell.setBorderRight(getBorder(cellStyle.getBorderRight(), cellStyle.getRightBorderColor(), cell));
pdfCell.setBorderTop(getBorder(cellStyle.getBorderTop(), cellStyle.getTopBorderColor(), cell));
}
private void setPdfCellFont(HSSFCell cell, Text text, String fontPath) throws IOException {
HSSFCellStyle cellStyle = cell.getCellStyle();
HSSFFont font = cellStyle.getFont(cell.getSheet().getWorkbook());
text.setFont(StringUtils.isEmpty(fontPath) ? PdfFontFactory.createFont() : PdfFontFactory.createFont(fontPath, PdfEncodings.IDENTITY_H));
text.setFontSize(font.getFontHeightInPoints());
// Set font color
HSSFColor hssfColor = font.getHSSFColor(cell.getSheet().getWorkbook());
if (hssfColor != null && hssfColor.getIndex() != 64) {
short[] triplet = hssfColor.getTriplet();
text.setFontColor(new DeviceRgb(triplet[0], triplet[1], triplet[2]));
}
// Set font styles
if (font.getBold()) text.setBold();
if (font.getItalic()) text.setItalic();
if (font.getUnderline() == 1) text.setUnderline(0.5f, -1f);
}
public static Border getBorder(BorderStyle borderStyle, short colorIndex, HSSFCell cell) {
HSSFPalette customPalette = cell.getSheet().getWorkbook().getCustomPalette();
HSSFColor color = customPalette.getColor(colorIndex);
Color defaultColor = (color != null && color.getIndex() != 64)
? new DeviceRgb(color.getTriplet()[0], color.getTriplet()[1], color.getTriplet()[2])
: ColorConstants.BLACK;
switch (borderStyle) {
case THIN:
return new SolidBorder(defaultColor, 0.3f);
case MEDIUM:
return new SolidBorder(defaultColor, 0.5f);
case DASHED:
return new DashedBorder(defaultColor, 0.3f);
case DOTTED:
return new DottedBorder(defaultColor, 0.3f);
case THICK:
return new SolidBorder(defaultColor, 1f);
case DOUBLE:
return new DoubleBorder(defaultColor, 0.3f);
case MEDIUM_DASHED:
return new DashedBorder(defaultColor, 0.5f);
default:
return Border.NO_BORDER;
}
}
}

View File

@ -0,0 +1,116 @@
package cn.idev.excel.fileconvertor.v03;
import com.itextpdf.io.image.ImageData;
import com.itextpdf.io.image.ImageDataFactory;
import com.itextpdf.kernel.geom.Rectangle;
import com.itextpdf.layout.element.Table;
import com.itextpdf.layout.renderer.CellRenderer;
import com.itextpdf.layout.renderer.DrawContext;
import com.itextpdf.layout.renderer.IRenderer;
import com.itextpdf.layout.renderer.TableRenderer;
import org.apache.poi.hssf.usermodel.HSSFClientAnchor;
import org.apache.poi.hssf.usermodel.HSSFPicture;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import java.util.List;
/**
* Renders images from an Excel sheet onto a PDF table.
*/
public class XlsImageTableRenderer extends TableRenderer {
private List<HSSFPicture> hSSFPictures;
private HSSFSheet sheet;
public XlsImageTableRenderer(Table modelElement, List<HSSFPicture> hSSFPictures, HSSFSheet sheet) {
super(modelElement);
this.hSSFPictures = hSSFPictures;
this.sheet = sheet;
}
@Override
public void drawChildren(DrawContext drawContext) {
super.drawChildren(drawContext);
drawExcelImages(drawContext);
}
private void drawExcelImages(DrawContext drawContext) {
for (HSSFPicture picture : hSSFPictures) {
HSSFClientAnchor clientAnchor = picture.getClientAnchor();
Rectangle imageRect = calculateImageRectangle(clientAnchor);
ImageData imageData = ImageDataFactory.create(picture.getPictureData().getData());
drawContext.getCanvas().addImage(imageData,
imageRect.getWidth(),
0,
0,
imageRect.getHeight(),
imageRect.getLeft(),
imageRect.getTop());
}
}
private Rectangle calculateImageRectangle(HSSFClientAnchor clientAnchor) {
CellRenderer cellRenderer1 = rows.get(clientAnchor.getRow1())[clientAnchor.getCol1()];
Rectangle rect1 = cellRenderer1.getOccupiedAreaBBox();
CellRenderer cellRenderer2 = rows.get(clientAnchor.getRow2())[clientAnchor.getCol2()];
Rectangle rect2 = cellRenderer2.getOccupiedAreaBBox();
float widthRate = calculateWidthRate(rect2);
float heightRate = calculateHeightRate(rect2);
float width = calculateImageWidth(clientAnchor, widthRate);
float height = calculateImageHeight(clientAnchor, heightRate);
float x = rect1.getLeft() + clientAnchor.getDx1() * widthRate;
float y = rect1.getTop() - height - clientAnchor.getDy1() * heightRate;
return new Rectangle(x, y, width, height);
}
private float calculateWidthRate(Rectangle rect2) {
return (super.getOccupiedAreaBBox().getWidth() + rect2.getWidth()) / getExcelWidth(sheet);
}
private float calculateHeightRate(Rectangle rect2) {
return (super.getOccupiedAreaBBox().getHeight() - rect2.getHeight()) / getExcelHeight(sheet);
}
private float calculateImageWidth(HSSFClientAnchor clientAnchor, float widthRate) {
float width = 0f;
for (int j = clientAnchor.getCol1(); j < clientAnchor.getCol2(); j++) {
width += sheet.getColumnWidth(j);
}
return Math.abs(width - clientAnchor.getDx1() + clientAnchor.getDx2()) * widthRate;
}
private float calculateImageHeight(HSSFClientAnchor clientAnchor, float heightRate) {
float height = 0f;
for (int j = clientAnchor.getRow1(); j < clientAnchor.getRow2(); j++) {
height += sheet.getRow(j).getHeight();
}
return Math.abs(height - clientAnchor.getDy1() + clientAnchor.getDy2()) * heightRate;
}
private float getExcelHeight(HSSFSheet sheet) {
int physicalNumberOfRows = sheet.getPhysicalNumberOfRows();
float result = 0;
for (int i = 0; i < physicalNumberOfRows; i++) {
result += sheet.getRow(i).getHeight();
}
return result;
}
private float getExcelWidth(HSSFSheet sheet) {
short lastCellNum = sheet.getRow(0).getLastCellNum();
float result = 0;
for (int i = 0; i < lastCellNum; i++) {
result += sheet.getColumnWidth(i);
}
return result;
}
@Override
public IRenderer getNextRenderer() {
return new XlsImageTableRenderer((Table) modelElement, hSSFPictures, sheet);
}
}

View File

@ -0,0 +1,161 @@
package cn.idev.excel.fileconvertor.v07;
import cn.idev.excel.fileconvertor.BaseExcelConverter;
import cn.idev.excel.fileconvertor.Excel2PdfUtils;
import cn.idev.excel.fileconvertor.FileConverterContext;
import cn.idev.excel.util.StringUtils;
import com.itextpdf.io.font.PdfEncodings;
import com.itextpdf.kernel.colors.DeviceRgb;
import com.itextpdf.kernel.font.PdfFontFactory;
import com.itextpdf.layout.borders.*;
import com.itextpdf.layout.element.Paragraph;
import com.itextpdf.layout.element.Table;
import com.itextpdf.layout.element.Text;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.*;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
public class XlsxConverter extends BaseExcelConverter {
private static final String DEFAULT_FONT_PATH = System.getProperty("user.dir") + "/doc/font/SimHei.TTF";
public XlsxConverter(FileConverterContext context) {
super(context);
}
@Override
public void addPicsToTable(Table table, Sheet sheet) {
XSSFDrawing drawing = (XSSFDrawing) sheet.createDrawingPatriarch();
if (drawing != null) {
List<XSSFPicture> pictures = new ArrayList<>();
for (XSSFShape shape : drawing.getShapes()) {
if (shape instanceof XSSFPicture) {
pictures.add((XSSFPicture) shape);
}
}
table.setNextRenderer(new XlsxImageTableRenderer(table, pictures, (XSSFSheet) sheet));
}
}
@Override
public com.itextpdf.layout.element.Cell convertCell(Cell cell, int rowspan, int colspan, float maxWidth, String fontPath) throws IOException {
String value = Excel2PdfUtils.getValue(cell);
com.itextpdf.layout.element.Cell pdfCell = createPdfCell(rowspan, colspan, cell, value, maxWidth, fontPath);
return pdfCell;
}
public static void transformBorder(XSSFCell cell, com.itextpdf.layout.element.Cell pdfCell) {
XSSFCellStyle cellStyle = cell.getCellStyle();
BorderStyle borderBottom = cellStyle.getBorderBottom();
pdfCell.setBorderBottom(getBorder(borderBottom, cellStyle.getBottomBorderXSSFColor()));
BorderStyle borderLeft = cellStyle.getBorderLeft();
pdfCell.setBorderLeft(getBorder(borderLeft, cellStyle.getLeftBorderXSSFColor()));
BorderStyle borderRight = cellStyle.getBorderRight();
pdfCell.setBorderRight(getBorder(borderRight, cellStyle.getRightBorderXSSFColor()));
BorderStyle borderTop = cellStyle.getBorderTop();
pdfCell.setBorderTop(getBorder(borderTop, cellStyle.getTopBorderXSSFColor()));
}
private com.itextpdf.layout.element.Cell createPdfCell(int rowspan, int colspan, Cell cell, String value, float maxWidth, String fontPath) throws IOException {
com.itextpdf.layout.element.Cell pdfCell = new com.itextpdf.layout.element.Cell(rowspan, colspan)
.setHeight(cell.getRow().getHeightInPoints() * 1.2f)
.setPadding(0);
Text text = new Text(value);
setPdfCellFont((XSSFCell) cell, text, fontPath);
Paragraph paragraph = new Paragraph(text).setPadding(0f).setMargin(0f);
XSSFCellStyle cellStyle = ((XSSFCell) cell).getCellStyle();
if (cellStyle.getWrapText()) {
paragraph.setMaxWidth(maxWidth);
}
pdfCell.add(paragraph);
setCellStyles((XSSFCell)cell, pdfCell);
return pdfCell;
}
private void setCellStyles( XSSFCell cell,com.itextpdf.layout.element.Cell pdfCell) throws IOException {
XSSFCellStyle cellStyle = cell.getCellStyle();
pdfCell.setVerticalAlignment(getVerticalAlignment(cellStyle.getVerticalAlignment()))
.setTextAlignment(getTextAlignment(cellStyle.getAlignment(), cell.getCellType()));
// Set borders and background color
setBorders(pdfCell, cellStyle);
setBackgroundColor(pdfCell, cellStyle);
}
private void setBorders(com.itextpdf.layout.element.Cell pdfCell, XSSFCellStyle cellStyle) {
pdfCell.setBorderBottom(getBorder(cellStyle.getBorderBottom(), cellStyle.getBottomBorderXSSFColor()));
pdfCell.setBorderLeft(getBorder(cellStyle.getBorderLeft(), cellStyle.getLeftBorderXSSFColor()));
pdfCell.setBorderRight(getBorder(cellStyle.getBorderRight(), cellStyle.getRightBorderXSSFColor()));
pdfCell.setBorderTop(getBorder(cellStyle.getBorderTop(), cellStyle.getTopBorderXSSFColor()));
}
private void setBackgroundColor(com.itextpdf.layout.element.Cell pdfCell, XSSFCellStyle cellStyle) {
XSSFColor fillColor = cellStyle.getFillForegroundXSSFColor();
if (fillColor != null) {
byte[] rgb = fillColor.getRGB();
if (rgb != null) {
pdfCell.setBackgroundColor(new DeviceRgb(Byte.toUnsignedInt(rgb[0]), Byte.toUnsignedInt(rgb[1]), Byte.toUnsignedInt(rgb[2])));
}
}
}
private void setPdfCellFont(XSSFCell cell, Text text,String fontPath) throws IOException {
XSSFCellStyle cellStyle = cell.getCellStyle();
short fontHeight = cellStyle.getFont().getFontHeightInPoints();
cellStyle.getFont().getFontName();
text.setFont(StringUtils.isEmpty(fontPath) ? PdfFontFactory.createFont() : PdfFontFactory.createFont(fontPath, PdfEncodings.IDENTITY_H));
text.setFontSize(fontHeight);
setFontColor(cellStyle.getFont(), text);
setFontStyles(cell.getCellStyle().getFont(), text);
}
private void setFontColor(XSSFFont font, Text text) {
XSSFColor xssfColor = font.getXSSFColor();
if (xssfColor != null && xssfColor.getIndex() != 64) {
byte[] rgb = xssfColor.getRGB();
if (rgb != null) {
text.setFontColor(new DeviceRgb(Byte.toUnsignedInt(rgb[0]), Byte.toUnsignedInt(rgb[1]), Byte.toUnsignedInt(rgb[2])));
}
}
}
private void setFontStyles(XSSFFont font, Text text) {
if (font.getBold()) text.setBold();
if (font.getItalic()) text.setItalic();
if (font.getUnderline() == 1) text.setUnderline(0.5f, -1f);
}
public static com.itextpdf.layout.borders.Border getBorder(BorderStyle borderStyle, XSSFColor xSSFColor) {
DeviceRgb defaultColor = new DeviceRgb(0, 0, 0); // Default to black
if (xSSFColor != null) {
byte[] rgb = xSSFColor.getRGB();
if (rgb != null) {
defaultColor = new DeviceRgb(Byte.toUnsignedInt(rgb[0]), Byte.toUnsignedInt(rgb[1]), Byte.toUnsignedInt(rgb[2]));
}
}
switch (borderStyle) {
case THIN:
return new SolidBorder(defaultColor, 0.3f);
case MEDIUM:
return new SolidBorder(defaultColor, 0.5f);
case DASHED:
return new DashedBorder(defaultColor, 0.3f);
case DOTTED:
return new DottedBorder(defaultColor, 0.3f);
case THICK:
return new SolidBorder(defaultColor, 1f);
case DOUBLE:
return new DoubleBorder(defaultColor, 0.3f);
case MEDIUM_DASHED:
return new DashedBorder(defaultColor, 0.5f);
default:
return Border.NO_BORDER;
}
}
}

View File

@ -0,0 +1,101 @@
package cn.idev.excel.fileconvertor.v07;
import com.itextpdf.io.image.ImageData;
import com.itextpdf.io.image.ImageDataFactory;
import com.itextpdf.kernel.geom.Rectangle;
import com.itextpdf.layout.element.Table;
import com.itextpdf.layout.renderer.CellRenderer;
import com.itextpdf.layout.renderer.DrawContext;
import com.itextpdf.layout.renderer.IRenderer;
import com.itextpdf.layout.renderer.TableRenderer;
import org.apache.poi.xssf.usermodel.XSSFClientAnchor;
import org.apache.poi.xssf.usermodel.XSSFPicture;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import java.util.List;
/**
* Renders images from an Excel sheet onto a PDF table.
*/
public class XlsxImageTableRenderer extends TableRenderer {
private List<XSSFPicture> xssfPictures;
private XSSFSheet sheet;
public XlsxImageTableRenderer(Table modelElement, List<XSSFPicture> xssfPictures, XSSFSheet sheet) {
super(modelElement);
this.xssfPictures = xssfPictures;
this.sheet = sheet;
}
@Override
public void drawChildren(DrawContext drawContext) {
super.drawChildren(drawContext);
renderExcelImages(drawContext);
}
private void renderExcelImages(DrawContext drawContext) {
for (XSSFPicture picture : xssfPictures) {
XSSFClientAnchor clientAnchor = picture.getClientAnchor();
Rectangle imageRect = calculateImageRectangle(clientAnchor);
ImageData imageData = ImageDataFactory.create(picture.getPictureData().getData());
drawContext.getCanvas().addImage(imageData,
imageRect.getWidth(),
0,
0,
imageRect.getHeight(),
imageRect.getLeft(),
imageRect.getTop());
}
}
private Rectangle calculateImageRectangle(XSSFClientAnchor clientAnchor) {
CellRenderer cellRenderer1 = rows.get(clientAnchor.getRow1())[clientAnchor.getCol1()];
CellRenderer cellRenderer2 = rows.get(clientAnchor.getRow2())[clientAnchor.getCol2()];
Rectangle rect1 = cellRenderer1.getOccupiedAreaBBox();
Rectangle rect2 = cellRenderer2.getOccupiedAreaBBox();
float widthRate = (super.getOccupiedAreaBBox().getWidth() + rect2.getWidth()) / getExcelWidth(sheet);
float heightRate = (super.getOccupiedAreaBBox().getHeight() - rect2.getHeight()) / getExcelHeight(sheet);
float width = calculateImageWidth(clientAnchor, widthRate);
float height = calculateImageHeight(clientAnchor, heightRate);
float x = rect1.getLeft() + clientAnchor.getDx1() * widthRate;
float y = rect1.getTop() - height - clientAnchor.getDy1() * heightRate;
return new Rectangle(x, y, width, height);
}
private float calculateImageWidth(XSSFClientAnchor clientAnchor, float widthRate) {
float width = 0f;
for (int j = clientAnchor.getCol1(); j < clientAnchor.getCol2(); j++) {
width += sheet.getColumnWidth(j);
}
return Math.abs(width - clientAnchor.getDx1() + clientAnchor.getDx2()) * widthRate;
}
private float calculateImageHeight(XSSFClientAnchor clientAnchor, float heightRate) {
float height = 0f;
for (int j = clientAnchor.getRow1(); j < clientAnchor.getRow2(); j++) {
height += sheet.getRow(j).getHeight();
}
return Math.abs(height - clientAnchor.getDy1() + clientAnchor.getDy2()) * heightRate;
}
private float getExcelHeight(XSSFSheet sheet) {
float totalHeight = 0;
for (int i = 0; i < sheet.getPhysicalNumberOfRows(); i++) {
totalHeight += sheet.getRow(i).getHeight();
}
return totalHeight;
}
private float getExcelWidth(XSSFSheet sheet) {
return (short)sheet.getRow(0).getLastCellNum() * sheet.getColumnWidth(0);
}
@Override
public IRenderer getNextRenderer() {
return new XlsxImageTableRenderer((Table) modelElement, xssfPictures, sheet);
}
}

View File

@ -211,6 +211,12 @@ public class ExcelReaderBuilder extends AbstractExcelReaderParameterBuilder<Exce
return this;
}
public ExcelReaderBuilder numRows(Integer numRows) {
readWorkbook.setNumRows(numRows);
return this;
}
public ExcelReader build() {
return new ExcelReader(readWorkbook);
}

View File

@ -51,6 +51,17 @@ public class ExcelReaderSheetBuilder extends AbstractExcelReaderParameterBuilder
return this;
}
/**
* numRows
*
* @param numRows
* @return
*/
public ExcelReaderSheetBuilder numRows(Integer numRows) {
readSheet.setNumRows(numRows);
return this;
}
public ReadSheet build() {
return readSheet;
}

View File

@ -17,7 +17,7 @@ public class PageReadListener<T> implements ReadListener<T> {
/**
* Default single handle the amount of data
*/
public static int BATCH_COUNT = 100;
public static int BATCH_COUNT = 1;
/**
* Temporary storage of data
*/

View File

@ -6,6 +6,9 @@ import cn.idev.excel.event.Listener;
import cn.idev.excel.context.AnalysisContext;
import cn.idev.excel.metadata.CellExtra;
import cn.idev.excel.metadata.data.ReadCellData;
import cn.idev.excel.read.metadata.holder.ReadRowHolder;
import cn.idev.excel.read.metadata.holder.ReadSheetHolder;
import cn.idev.excel.read.metadata.holder.ReadWorkbookHolder;
/**
* Interface to listen for read results
@ -31,7 +34,8 @@ public interface ReadListener<T> extends Listener {
* @param headMap
* @param context
*/
default void invokeHead(Map<Integer, ReadCellData<?>> headMap, AnalysisContext context) {}
default void invokeHead(Map<Integer, ReadCellData<?>> headMap, AnalysisContext context) {
}
/**
* When analysis one row trigger invoke function.
@ -47,7 +51,8 @@ public interface ReadListener<T> extends Listener {
* @param extra extra information
* @param context analysis context
*/
default void extra(CellExtra extra, AnalysisContext context) {}
default void extra(CellExtra extra, AnalysisContext context) {
}
/**
* if have something to do after all analysis
@ -63,6 +68,24 @@ public interface ReadListener<T> extends Listener {
* @return
*/
default boolean hasNext(AnalysisContext context) {
if (context == null
|| context.readRowHolder() == null
|| context.readSheetHolder() == null
|| context.readSheetHolder().getReadSheet() == null
|| context.readWorkbookHolder().getReadWorkbook() == null
) {
return true;
}
ReadRowHolder readRowHolder = context.readRowHolder();
int index = readRowHolder.getRowIndex();
Integer limit = context.readSheetHolder().getReadSheet().getNumRows();
if (limit == null) {
limit = context.readWorkbookHolder().getReadWorkbook().getNumRows();
}
if (limit != null && index >= limit) {
return false;
}
return true;
}
}

View File

@ -15,6 +15,11 @@ public class ReadSheet extends ReadBasicParameter {
*/
private String sheetName;
/**
* The number of rows to read, the default is all, start with 0.
*/
public Integer numRows;
public ReadSheet() {}
public ReadSheet(Integer sheetNo) {
@ -26,6 +31,12 @@ public class ReadSheet extends ReadBasicParameter {
this.sheetName = sheetName;
}
public ReadSheet(Integer sheetNo, String sheetName,Integer numRows) {
this.sheetNo = sheetNo;
this.sheetName = sheetName;
this.numRows = numRows;
}
public Integer getSheetNo() {
return sheetNo;
}
@ -42,6 +53,15 @@ public class ReadSheet extends ReadBasicParameter {
this.sheetName = sheetName;
}
public Integer getNumRows() {
return numRows;
}
public void setNumRows(Integer numRows) {
this.numRows = numRows;
}
public void copyBasicParameter(ReadSheet other) {
if (other == null) {
return;
@ -53,6 +73,7 @@ public class ReadSheet extends ReadBasicParameter {
this.setCustomConverterList(other.getCustomConverterList());
this.setAutoTrim(other.getAutoTrim());
this.setUse1904windowing(other.getUse1904windowing());
this.setNumRows(other.getNumRows());
}
@Override

View File

@ -115,4 +115,9 @@ public class ReadWorkbook extends ReadBasicParameter {
* @see CellExtraTypeEnum
*/
private Set<CellExtraTypeEnum> extraReadSet;
/**
* The number of rows to read, the default is all, start with 0.
*/
private Integer numRows;
}

View File

@ -118,6 +118,7 @@ public class DefaultAnalysisEventProcessor implements AnalysisEventProcessor {
throw new ExcelAnalysisStopException();
}
}
}
private void buildHead(AnalysisContext analysisContext, Map<Integer, ReadCellData<?>> cellDataMap) {

View File

@ -53,7 +53,7 @@ public class ReadTest {
for (DemoData demoData : dataList) {
log.info("读取到一条数据{}", JSON.toJSONString(demoData));
}
})).sheet().doRead();
})).numRows(2).sheet().doRead();
// 写法2
// 匿名内部类 不用额外写一个DemoDataListener
@ -105,6 +105,7 @@ public class ReadTest {
try (ExcelReader excelReader = EasyExcel.read(fileName, DemoData.class, new DemoDataListener()).build()) {
// 构建一个sheet 这里可以指定名字或者no
ReadSheet readSheet = EasyExcel.readSheet(0).build();
readSheet.setNumRows(2);
// 读取一个sheet
excelReader.read(readSheet);
}
@ -124,7 +125,7 @@ public class ReadTest {
public void indexOrNameRead() {
String fileName = TestFileUtil.getPath() + "demo" + File.separator + "demo.xlsx";
// 这里默认读取第一个sheet
EasyExcel.read(fileName, IndexOrNameData.class, new IndexOrNameDataListener()).sheet().doRead();
EasyExcel.read(fileName, IndexOrNameData.class, new IndexOrNameDataListener()).numRows(1).sheet().doRead();
}
/**

Binary file not shown.

Before

Width:  |  Height:  |  Size: 0 B

After

Width:  |  Height:  |  Size: 12 KiB