在 XSSFWorkbook 中调整 EMF 图像的大小

Resizing an EMF image in XSSFWorkbook

我试图在将 EMF 图像插入 XSSFWorkbook 后调整其大小。 支持调整 PNGJPEGDIB 图片大小。

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 中代码相同的方法 scaleCellresizeHemfPicture 方法将 Picture 大小调整为 HemfPicture 维度。

这已经过测试,可以使用 apache poi 5.0.0Java 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();

 }
}