在 XSSFWorkbook 中调整 EMF 图像的大小
Resizing an EMF image in XSSFWorkbook
我试图在将 EMF
图像插入 XSSFWorkbook
后调整其大小。
支持调整 PNG
、JPEG
和 DIB
图片大小。
private void addNormalFigure(XSSFSheet sheet, byte[] imgData){
XSSFWorkbook w = sheet.getWorkbook();
int picIdx = w.addPicture(imgData, Workbook.PICTURE_TYPE_EMF);
CreationHelper helper = w.getCreationHelper();
XSSFDrawing drawing = sheet.createDrawingPatriarch();
ClientAnchor anchor = helper.createClientAnchor();
// Column : A
anchor.setCol1(0);
// Row : 4
anchor.setRow1(4);
Picture pic = drawing.createPicture(anchor, picIdx);
double height = 2.0;
double width = 2.0;
// sets the anchor.col2 to 0 and anchor.row2 to 0
pic.getImageDimension().setSize(inchToPixel(width), inchToPixel(height));
// pic.resize(); -> this too sets the anchor.col2 to 0 and anchor.row2 to 0
}
private double inchToPixel(double in) {
return in * 96.0;
}
有什么方法可以解决这个问题吗?
Apache poi
未提供从 Picture
类型 Workbook.PICTURE_TYPE_EMF
获取图像尺寸的功能。使用的ImageUtils
方法getImageDimension
只能从JPEG,PNG和DIB图片中获取尺寸,
但是apache poi
提供了org.apache.poi.hemf.usermodel.HemfPicture
。所以
import org.apache.poi.hemf.usermodel.HemfPicture;
...
HemfPicture hemfPicture = new HemfPicture(new ByteArrayInputStream(imgData));
System.out.println(hemfPicture.getSize());
...
将打印正确的尺寸。
但是它无法将这些维度设置为锚点。 ImageUtils
中有方法 scaleCell
但 public 无法访问。所以唯一的方法是将该方法的源代码复制到您的代码中。
下面的完整示例就是这样做的。它使用与 ImageUtils
中代码相同的方法 scaleCell
。 resizeHemfPicture
方法将 Picture
大小调整为 HemfPicture
维度。
这已经过测试,可以使用 apache poi 5.0.0
和 Java 12
。
import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.xssf.usermodel.*;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.util.IOUtils;
import org.apache.poi.util.Units;
import org.apache.poi.ss.util.ImageUtils;
import org.apache.poi.hemf.usermodel.HemfPicture;
import java.util.function.Consumer;
import java.util.function.Function;
import java.awt.Dimension;
import java.io.FileInputStream;
import java.io.ByteArrayInputStream;
import java.io.FileOutputStream;
class CreateExcelEMFPicture {
public static double getRowHeightInPixels(Sheet sheet, int rowNum) {
Row r = sheet.getRow(rowNum);
double points = (r == null) ? sheet.getDefaultRowHeightInPoints() : r.getHeightInPoints();
return Units.toEMU(points)/(double)Units.EMU_PER_PIXEL;
}
private static void scaleCell(final double targetSize,
final int startCell,
final int startD,
Consumer<Integer> endCell,
Consumer<Integer> endD,
final int hssfUnits,
Function<Integer,Number> nextSize) {
if (targetSize < 0) {
throw new IllegalArgumentException("target size < 0");
}
int cellIdx = startCell;
double dim, delta;
for (double totalDim = 0, remDim;; cellIdx++, totalDim += remDim) {
dim = nextSize.apply(cellIdx).doubleValue();
remDim = dim;
if (cellIdx == startCell) {
if (hssfUnits > 0) {
remDim *= 1 - startD/(double)hssfUnits;
} else {
remDim -= startD/(double)Units.EMU_PER_PIXEL;
}
}
delta = targetSize - totalDim;
if (delta < remDim) {
break;
}
}
double endDval;
if (hssfUnits > 0) {
endDval = delta/dim * (double)hssfUnits;
} else {
endDval = delta * Units.EMU_PER_PIXEL;
}
if (cellIdx == startCell) {
endDval += startD;
}
endCell.accept(cellIdx);
endD.accept((int)Math.rint(endDval));
}
static void resizeHemfPicture(Picture picture, HemfPicture hemfPicture) {
ClientAnchor anchor = picture.getClientAnchor();
boolean isHSSF = (anchor instanceof HSSFClientAnchor);
double height = hemfPicture.getSize().getHeight();
double width = hemfPicture.getSize().getWidth();
Sheet sheet = picture.getSheet();
int WIDTH_UNITS = 1024;
int HEIGHT_UNITS = 256;
scaleCell(width, anchor.getCol1(), anchor.getDx1(), anchor::setCol2, anchor::setDx2, isHSSF ? WIDTH_UNITS : 0, sheet::getColumnWidthInPixels);
scaleCell(height, anchor.getRow1(), anchor.getDy1(), anchor::setRow2, anchor::setDy2, isHSSF ? HEIGHT_UNITS : 0, (row) -> getRowHeightInPixels(sheet, row));
}
public static void main(String[] args) throws Exception{
Workbook workbook = new XSSFWorkbook(); String filePath = "./CreateExcelEMFPicture.xlsx";
//Workbook workbook = new HSSFWorkbook(); String filePath = "./CreateExcelEMFPicture.xls";
CreationHelper helper = workbook.getCreationHelper();
//add picture data to this workbook.
FileInputStream is = new FileInputStream("./image.emf");
byte[] bytes = IOUtils.toByteArray(is);
int pictureIdx = workbook.addPicture(bytes, Workbook.PICTURE_TYPE_EMF);
is.close();
HemfPicture hemfPicture = new HemfPicture(new ByteArrayInputStream(bytes));
System.out.println(hemfPicture.getSize()); // returns correct dimension
Sheet sheet = workbook.createSheet("Sheet1");
Drawing drawing = sheet.createDrawingPatriarch();
ClientAnchor anchor = helper.createClientAnchor();
anchor.setCol1(0);
anchor.setRow1(4);
Picture picture = drawing.createPicture(anchor, pictureIdx);
System.out.println(picture.getImageDimension()); // 0, 0
System.out.println(ImageUtils.getDimensionFromAnchor(picture)); // 0, 0
//picture.resize(); //will not work
resizeHemfPicture(picture, hemfPicture);
System.out.println(ImageUtils.getDimensionFromAnchor(picture)); // correct dimension
FileOutputStream out = new FileOutputStream(filePath);
workbook.write(out);
out.close();
workbook.close();
}
}
我试图在将 EMF
图像插入 XSSFWorkbook
后调整其大小。
支持调整 PNG
、JPEG
和 DIB
图片大小。
private void addNormalFigure(XSSFSheet sheet, byte[] imgData){
XSSFWorkbook w = sheet.getWorkbook();
int picIdx = w.addPicture(imgData, Workbook.PICTURE_TYPE_EMF);
CreationHelper helper = w.getCreationHelper();
XSSFDrawing drawing = sheet.createDrawingPatriarch();
ClientAnchor anchor = helper.createClientAnchor();
// Column : A
anchor.setCol1(0);
// Row : 4
anchor.setRow1(4);
Picture pic = drawing.createPicture(anchor, picIdx);
double height = 2.0;
double width = 2.0;
// sets the anchor.col2 to 0 and anchor.row2 to 0
pic.getImageDimension().setSize(inchToPixel(width), inchToPixel(height));
// pic.resize(); -> this too sets the anchor.col2 to 0 and anchor.row2 to 0
}
private double inchToPixel(double in) {
return in * 96.0;
}
有什么方法可以解决这个问题吗?
Apache poi
未提供从 Picture
类型 Workbook.PICTURE_TYPE_EMF
获取图像尺寸的功能。使用的ImageUtils
方法getImageDimension
只能从JPEG,PNG和DIB图片中获取尺寸,
但是apache poi
提供了org.apache.poi.hemf.usermodel.HemfPicture
。所以
import org.apache.poi.hemf.usermodel.HemfPicture;
...
HemfPicture hemfPicture = new HemfPicture(new ByteArrayInputStream(imgData));
System.out.println(hemfPicture.getSize());
...
将打印正确的尺寸。
但是它无法将这些维度设置为锚点。 ImageUtils
中有方法 scaleCell
但 public 无法访问。所以唯一的方法是将该方法的源代码复制到您的代码中。
下面的完整示例就是这样做的。它使用与 ImageUtils
中代码相同的方法 scaleCell
。 resizeHemfPicture
方法将 Picture
大小调整为 HemfPicture
维度。
这已经过测试,可以使用 apache poi 5.0.0
和 Java 12
。
import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.xssf.usermodel.*;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.util.IOUtils;
import org.apache.poi.util.Units;
import org.apache.poi.ss.util.ImageUtils;
import org.apache.poi.hemf.usermodel.HemfPicture;
import java.util.function.Consumer;
import java.util.function.Function;
import java.awt.Dimension;
import java.io.FileInputStream;
import java.io.ByteArrayInputStream;
import java.io.FileOutputStream;
class CreateExcelEMFPicture {
public static double getRowHeightInPixels(Sheet sheet, int rowNum) {
Row r = sheet.getRow(rowNum);
double points = (r == null) ? sheet.getDefaultRowHeightInPoints() : r.getHeightInPoints();
return Units.toEMU(points)/(double)Units.EMU_PER_PIXEL;
}
private static void scaleCell(final double targetSize,
final int startCell,
final int startD,
Consumer<Integer> endCell,
Consumer<Integer> endD,
final int hssfUnits,
Function<Integer,Number> nextSize) {
if (targetSize < 0) {
throw new IllegalArgumentException("target size < 0");
}
int cellIdx = startCell;
double dim, delta;
for (double totalDim = 0, remDim;; cellIdx++, totalDim += remDim) {
dim = nextSize.apply(cellIdx).doubleValue();
remDim = dim;
if (cellIdx == startCell) {
if (hssfUnits > 0) {
remDim *= 1 - startD/(double)hssfUnits;
} else {
remDim -= startD/(double)Units.EMU_PER_PIXEL;
}
}
delta = targetSize - totalDim;
if (delta < remDim) {
break;
}
}
double endDval;
if (hssfUnits > 0) {
endDval = delta/dim * (double)hssfUnits;
} else {
endDval = delta * Units.EMU_PER_PIXEL;
}
if (cellIdx == startCell) {
endDval += startD;
}
endCell.accept(cellIdx);
endD.accept((int)Math.rint(endDval));
}
static void resizeHemfPicture(Picture picture, HemfPicture hemfPicture) {
ClientAnchor anchor = picture.getClientAnchor();
boolean isHSSF = (anchor instanceof HSSFClientAnchor);
double height = hemfPicture.getSize().getHeight();
double width = hemfPicture.getSize().getWidth();
Sheet sheet = picture.getSheet();
int WIDTH_UNITS = 1024;
int HEIGHT_UNITS = 256;
scaleCell(width, anchor.getCol1(), anchor.getDx1(), anchor::setCol2, anchor::setDx2, isHSSF ? WIDTH_UNITS : 0, sheet::getColumnWidthInPixels);
scaleCell(height, anchor.getRow1(), anchor.getDy1(), anchor::setRow2, anchor::setDy2, isHSSF ? HEIGHT_UNITS : 0, (row) -> getRowHeightInPixels(sheet, row));
}
public static void main(String[] args) throws Exception{
Workbook workbook = new XSSFWorkbook(); String filePath = "./CreateExcelEMFPicture.xlsx";
//Workbook workbook = new HSSFWorkbook(); String filePath = "./CreateExcelEMFPicture.xls";
CreationHelper helper = workbook.getCreationHelper();
//add picture data to this workbook.
FileInputStream is = new FileInputStream("./image.emf");
byte[] bytes = IOUtils.toByteArray(is);
int pictureIdx = workbook.addPicture(bytes, Workbook.PICTURE_TYPE_EMF);
is.close();
HemfPicture hemfPicture = new HemfPicture(new ByteArrayInputStream(bytes));
System.out.println(hemfPicture.getSize()); // returns correct dimension
Sheet sheet = workbook.createSheet("Sheet1");
Drawing drawing = sheet.createDrawingPatriarch();
ClientAnchor anchor = helper.createClientAnchor();
anchor.setCol1(0);
anchor.setRow1(4);
Picture picture = drawing.createPicture(anchor, pictureIdx);
System.out.println(picture.getImageDimension()); // 0, 0
System.out.println(ImageUtils.getDimensionFromAnchor(picture)); // 0, 0
//picture.resize(); //will not work
resizeHemfPicture(picture, hemfPicture);
System.out.println(ImageUtils.getDimensionFromAnchor(picture)); // correct dimension
FileOutputStream out = new FileOutputStream(filePath);
workbook.write(out);
out.close();
workbook.close();
}
}