通过 POI 获取图片在 Excel 表格中的位置
POI 目前的版本,只提供了获取 Excel 表格中图片内容的方法(workbook.getAllPictures),但无法通过这个方法获得每个图片所在的位置,通过直接深入 Excel Record 数据,其实可以取出 Excel 表格每个内嵌对象的位置信息(ClientAnchorInfo),可惜位置信息中又不包含图片内容,所以,只能简单的假定,这两个方法所返回的列表,应该是一一对应的,通过这个假定,或许可以成功取到每个图片的位置信息,既其中心点所在的单元格。直接的应用之一,就是在导入人员等信息时,可以导入照片。
上代码:
获取位置
public static List<MyPictureData> getAllPictures(HSSFWorkbook workbook) {
List<MyPictureData> list = new ArrayList<MyPictureData>();
List<HSSFPictureData> pictureList = workbook.getAllPictures();
List<ClientAnchorInfo> clientAnchorRecords = getClientAnchorRecords(workbook);
if (pictureList.size() != clientAnchorRecords.size()) {
throw new RuntimeException("解析文件中的图片信息出错,找到的图片数量和图片位置信息数量不匹配");
}
for (int i = 0; i < pictureList.size(); i++) {
HSSFPictureData pictureData = pictureList.get(i);
ClientAnchorInfo anchor = clientAnchorRecords.get(i);
HSSFSheet sheet = anchor.sheet;
EscherClientAnchorRecord clientAnchorRecord = anchor.clientAnchorRecord;
list.add(new MyPictureData(workbook, sheet, pictureData, clientAnchorRecord));
}
return list ;
}
private static class ClientAnchorInfo {
public HSSFSheet sheet;
public EscherClientAnchorRecord clientAnchorRecord;
public ClientAnchorInfo(HSSFSheet sheet, EscherClientAnchorRecord clientAnchorRecord) {
super();
this.sheet = sheet;
this.clientAnchorRecord = clientAnchorRecord;
}
}
private static List<ClientAnchorInfo> getClientAnchorRecords(HSSFWorkbook workbook) {
List<ClientAnchorInfo> list = new ArrayList<ClientAnchorInfo>();
EscherAggregate drawingAggregate = null;
HSSFSheet sheet = null;
List<EscherRecord> recordList = null;
Iterator<EscherRecord> recordIter = null;
int numSheets = workbook.getNumberOfSheets();
for(int i = 0; i < numSheets; i++) {
sheet = workbook.getSheetAt(i);
drawingAggregate = sheet.getDrawingEscherAggregate();
if(drawingAggregate != null) {
recordList = drawingAggregate.getEscherRecords();
recordIter = recordList.iterator();
while(recordIter.hasNext()) {
getClientAnchorRecords(sheet, recordIter.next(), 1, list);
}
}
}
return list;
}
private static void getClientAnchorRecords(HSSFSheet sheet, EscherRecord escherRecord, int level, List<ClientAnchorInfo> list) {
List<EscherRecord> recordList = null;
Iterator<EscherRecord> recordIter = null;
EscherRecord childRecord = null;
recordList = escherRecord.getChildRecords();
recordIter = recordList.iterator();
while(recordIter.hasNext()) {
childRecord = recordIter.next();
if(childRecord instanceof EscherClientAnchorRecord) {
ClientAnchorInfo e = new ClientAnchorInfo(sheet, (EscherClientAnchorRecord) childRecord);
list.add(e);
}
if(childRecord.getChildRecords().size() > 0) {
getClientAnchorRecords(sheet, childRecord, level+1, list);
}
}
}
List<MyPictureData> list = new ArrayList<MyPictureData>();
List<HSSFPictureData> pictureList = workbook.getAllPictures();
List<ClientAnchorInfo> clientAnchorRecords = getClientAnchorRecords(workbook);
if (pictureList.size() != clientAnchorRecords.size()) {
throw new RuntimeException("解析文件中的图片信息出错,找到的图片数量和图片位置信息数量不匹配");
}
for (int i = 0; i < pictureList.size(); i++) {
HSSFPictureData pictureData = pictureList.get(i);
ClientAnchorInfo anchor = clientAnchorRecords.get(i);
HSSFSheet sheet = anchor.sheet;
EscherClientAnchorRecord clientAnchorRecord = anchor.clientAnchorRecord;
list.add(new MyPictureData(workbook, sheet, pictureData, clientAnchorRecord));
}
return list ;
}
private static class ClientAnchorInfo {
public HSSFSheet sheet;
public EscherClientAnchorRecord clientAnchorRecord;
public ClientAnchorInfo(HSSFSheet sheet, EscherClientAnchorRecord clientAnchorRecord) {
super();
this.sheet = sheet;
this.clientAnchorRecord = clientAnchorRecord;
}
}
private static List<ClientAnchorInfo> getClientAnchorRecords(HSSFWorkbook workbook) {
List<ClientAnchorInfo> list = new ArrayList<ClientAnchorInfo>();
EscherAggregate drawingAggregate = null;
HSSFSheet sheet = null;
List<EscherRecord> recordList = null;
Iterator<EscherRecord> recordIter = null;
int numSheets = workbook.getNumberOfSheets();
for(int i = 0; i < numSheets; i++) {
sheet = workbook.getSheetAt(i);
drawingAggregate = sheet.getDrawingEscherAggregate();
if(drawingAggregate != null) {
recordList = drawingAggregate.getEscherRecords();
recordIter = recordList.iterator();
while(recordIter.hasNext()) {
getClientAnchorRecords(sheet, recordIter.next(), 1, list);
}
}
}
return list;
}
private static void getClientAnchorRecords(HSSFSheet sheet, EscherRecord escherRecord, int level, List<ClientAnchorInfo> list) {
List<EscherRecord> recordList = null;
Iterator<EscherRecord> recordIter = null;
EscherRecord childRecord = null;
recordList = escherRecord.getChildRecords();
recordIter = recordList.iterator();
while(recordIter.hasNext()) {
childRecord = recordIter.next();
if(childRecord instanceof EscherClientAnchorRecord) {
ClientAnchorInfo e = new ClientAnchorInfo(sheet, (EscherClientAnchorRecord) childRecord);
list.add(e);
}
if(childRecord.getChildRecords().size() > 0) {
getClientAnchorRecords(sheet, childRecord, level+1, list);
}
}
}
相关类,计算中心单元格
package com.ultrapower.imonitor.emcc.dao.utils;
import org.apache.poi.ddf.EscherClientAnchorRecord;
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;
public class MyPictureData {
private final HSSFWorkbook workbook;
private final HSSFSheet sheet;
private final HSSFPictureData pictureData;
private final EscherClientAnchorRecord clientAnchor;
public MyPictureData(HSSFWorkbook workbook, HSSFSheet sheet, HSSFPictureData pictureData, EscherClientAnchorRecord clientAnchor) {
this.workbook = workbook;
this.sheet = sheet;
this.pictureData = pictureData;
this.clientAnchor = clientAnchor;
}
public HSSFWorkbook getWorkbook() {
return workbook;
}
public HSSFSheet getSheet() {
return sheet;
}
public EscherClientAnchorRecord getClientAnchor() {
return clientAnchor;
}
public HSSFPictureData getPictureData() {
return pictureData;
}
public byte[] getData() {
return pictureData.getData();
}
public String suggestFileExtension() {
return pictureData.suggestFileExtension();
}
/**
* 推测图片中心所覆盖的单元格,这个值不一定准确,但通常有效
*
* @return the row0
*/
public short getRow0() {
int row1 = getRow1();
int row2 = getRow2();
if (row1 == row2) {
return (short) row1;
}
int heights[] = new int[row2-row1+1];
for (int i = 0; i < heights.length; i++) {
heights[i] = getRowHeight(row1 + i);
}
// HSSFClientAnchor 中 dx 只能在 0-1023 之间,dy 只能在 0-255 之间
// 表示相对位置的比率,不是绝对值
int dy1 = getDy1() * heights[0] / 255;
int dy2 = getDy2() * heights[heights.length-1] / 255;
return (short) (getCenter(heights, dy1, dy2) + row1);
}
private short getRowHeight(int rowIndex) {
HSSFRow row = sheet.getRow(rowIndex);
short h = row == null? sheet.getDefaultRowHeight() : row.getHeight();
return h;
}
/**
* 推测图片中心所覆盖的单元格,这个值不一定准确,但通常有效
*
* @return the col0
*/
public short getCol0() {
short col1 = getCol1();
short col2 = getCol2();
if (col1 == col2) {
return col1;
}
int widths[] = new int[col2-col1+1];
for (int i = 0; i < widths.length; i++) {
widths[i] = sheet.getColumnWidth(col1 + i);
}
// HSSFClientAnchor 中 dx 只能在 0-1023 之间,dy 只能在 0-255 之间
// 表示相对位置的比率,不是绝对值
int dx1 = getDx1() * widths[0] / 1023;
int dx2 = getDx2() * widths[widths.length-1] / 1023;
return (short) (getCenter(widths, dx1, dx2) + col1);
}
/**
* 给定各线段的长度,以及起点相对于起点段的偏移量,终点相对于终点段的偏移量,
* 求中心点所在的线段
*
* @param a the a 各线段的长度
* @param d1 the d1 起点相对于起点段
* @param d2 the d2 终点相对于终点段的偏移量
*
* @return the center
*/
protected static int getCenter(int[] a, int d1, int d2) {
// 线段长度
int width = a[0] - d1 + d2;
for (int i = 1; i < a.length-1; i++) {
width += a[i];
}
// 中心点位置
int c = width / 2 + d1;
int x = a[0];
int cno = 0;
while (c > x) {
x += a[cno];
cno++;
}
return cno;
}
/**
* 左上角所在列
*
* @return the col1
*/
public short getCol1() {
return clientAnchor.getCol1();
}
/**
* 右下角所在的列
*
* @return the col2
*/
public short getCol2() {
return clientAnchor.getCol2();
}
/**
* 左上角的相对偏移量
*
* @return the dx1
*/
public short getDx1() {
return clientAnchor.getDx1();
}
/**
* 右下角的相对偏移量
*
* @return the dx2
*/
public short getDx2() {
return clientAnchor.getDx2();
}
/**
* 左上角的相对偏移量
*
* @return the dy1
*/
public short getDy1() {
return clientAnchor.getDy1();
}
/**
* 右下角的相对偏移量
*
* @return the dy2
*/
public short getDy2() {
return clientAnchor.getDy2();
}
/**
* 左上角所在的行
*
* @return the row1
*/
public short getRow1() {
return clientAnchor.getRow1();
}
/**
* 右下角所在的行
*
* @return the row2
*/
public short getRow2() {
return clientAnchor.getRow2();
}
}
import org.apache.poi.ddf.EscherClientAnchorRecord;
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;
public class MyPictureData {
private final HSSFWorkbook workbook;
private final HSSFSheet sheet;
private final HSSFPictureData pictureData;
private final EscherClientAnchorRecord clientAnchor;
public MyPictureData(HSSFWorkbook workbook, HSSFSheet sheet, HSSFPictureData pictureData, EscherClientAnchorRecord clientAnchor) {
this.workbook = workbook;
this.sheet = sheet;
this.pictureData = pictureData;
this.clientAnchor = clientAnchor;
}
public HSSFWorkbook getWorkbook() {
return workbook;
}
public HSSFSheet getSheet() {
return sheet;
}
public EscherClientAnchorRecord getClientAnchor() {
return clientAnchor;
}
public HSSFPictureData getPictureData() {
return pictureData;
}
public byte[] getData() {
return pictureData.getData();
}
public String suggestFileExtension() {
return pictureData.suggestFileExtension();
}
/**
* 推测图片中心所覆盖的单元格,这个值不一定准确,但通常有效
*
* @return the row0
*/
public short getRow0() {
int row1 = getRow1();
int row2 = getRow2();
if (row1 == row2) {
return (short) row1;
}
int heights[] = new int[row2-row1+1];
for (int i = 0; i < heights.length; i++) {
heights[i] = getRowHeight(row1 + i);
}
// HSSFClientAnchor 中 dx 只能在 0-1023 之间,dy 只能在 0-255 之间
// 表示相对位置的比率,不是绝对值
int dy1 = getDy1() * heights[0] / 255;
int dy2 = getDy2() * heights[heights.length-1] / 255;
return (short) (getCenter(heights, dy1, dy2) + row1);
}
private short getRowHeight(int rowIndex) {
HSSFRow row = sheet.getRow(rowIndex);
short h = row == null? sheet.getDefaultRowHeight() : row.getHeight();
return h;
}
/**
* 推测图片中心所覆盖的单元格,这个值不一定准确,但通常有效
*
* @return the col0
*/
public short getCol0() {
short col1 = getCol1();
short col2 = getCol2();
if (col1 == col2) {
return col1;
}
int widths[] = new int[col2-col1+1];
for (int i = 0; i < widths.length; i++) {
widths[i] = sheet.getColumnWidth(col1 + i);
}
// HSSFClientAnchor 中 dx 只能在 0-1023 之间,dy 只能在 0-255 之间
// 表示相对位置的比率,不是绝对值
int dx1 = getDx1() * widths[0] / 1023;
int dx2 = getDx2() * widths[widths.length-1] / 1023;
return (short) (getCenter(widths, dx1, dx2) + col1);
}
/**
* 给定各线段的长度,以及起点相对于起点段的偏移量,终点相对于终点段的偏移量,
* 求中心点所在的线段
*
* @param a the a 各线段的长度
* @param d1 the d1 起点相对于起点段
* @param d2 the d2 终点相对于终点段的偏移量
*
* @return the center
*/
protected static int getCenter(int[] a, int d1, int d2) {
// 线段长度
int width = a[0] - d1 + d2;
for (int i = 1; i < a.length-1; i++) {
width += a[i];
}
// 中心点位置
int c = width / 2 + d1;
int x = a[0];
int cno = 0;
while (c > x) {
x += a[cno];
cno++;
}
return cno;
}
/**
* 左上角所在列
*
* @return the col1
*/
public short getCol1() {
return clientAnchor.getCol1();
}
/**
* 右下角所在的列
*
* @return the col2
*/
public short getCol2() {
return clientAnchor.getCol2();
}
/**
* 左上角的相对偏移量
*
* @return the dx1
*/
public short getDx1() {
return clientAnchor.getDx1();
}
/**
* 右下角的相对偏移量
*
* @return the dx2
*/
public short getDx2() {
return clientAnchor.getDx2();
}
/**
* 左上角的相对偏移量
*
* @return the dy1
*/
public short getDy1() {
return clientAnchor.getDy1();
}
/**
* 右下角的相对偏移量
*
* @return the dy2
*/
public short getDy2() {
return clientAnchor.getDy2();
}
/**
* 左上角所在的行
*
* @return the row1
*/
public short getRow1() {
return clientAnchor.getRow1();
}
/**
* 右下角所在的行
*
* @return the row2
*/
public short getRow2() {
return clientAnchor.getRow2();
}
}