You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何解决XSSFWorkbook插入EMF图片后无法正常调整尺寸的问题

解决思路

POI 原生不支持读取 EMF 格式图片的原始维度,所以调用resize()或者直接修改ImageDimension都会失效,变通方案是跳过自带的尺寸计算逻辑,手动计算ClientAnchor的结束列、结束行以及偏移量,直接固定图片的展示尺寸。

具体实现代码

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();

    // 固定起始位置:A列,第4行
    anchor.setCol1(0);
    anchor.setRow1(4);
    // 起始位置无偏移
    anchor.setDx1(0);
    anchor.setDy1(0);

    // 目标尺寸:2英寸宽,2英寸高,先转成EMU单位(1英寸=914400 EMU)
    long targetWidthEmu = inchToEmu(2.0);
    long targetHeightEmu = inchToEmu(2.0);

    // 计算结束列和列偏移
    int col2 = anchor.getCol1();
    long remainingWidth = targetWidthEmu;
    while (remainingWidth > 0 && col2 < 16384) { // Excel最大列数是16384
        long colWidthEmu = getColumnWidthEmu(sheet, col2);
        if (remainingWidth <= colWidthEmu) {
            anchor.setDx2((int) remainingWidth);
            break;
        } else {
            remainingWidth -= colWidthEmu;
            col2++;
        }
    }
    anchor.setCol2(col2);

    // 计算结束行和行偏移
    int row2 = anchor.getRow1();
    long remainingHeight = targetHeightEmu;
    while (remainingHeight > 0 && row2 < 1048576) { // Excel最大行数是1048576
        long rowHeightEmu = getRowHeightEmu(sheet, row2);
        if (remainingHeight <= rowHeightEmu) {
            anchor.setDy2((int) remainingHeight);
            break;
        } else {
            remainingHeight -= rowHeightEmu;
            row2++;
        }
    }
    anchor.setRow2(row2);

    // 直接创建图片即可,不需要再调用resize
    drawing.createPicture(anchor, picIdx);
}

// 英寸转EMU单位
private long inchToEmu(double inch) {
    return (long) (inch * 914400);
}

// 获取指定列的宽度,单位EMU
private long getColumnWidthEmu(XSSFSheet sheet, int colIndex) {
    int widthPx = sheet.getColumnWidthInPixels(colIndex);
    // 像素转EMU:96像素=1英寸=914400EMU
    return (long) (widthPx * 914400.0 / 96);
}

// 获取指定行的高度,单位EMU
private long getRowHeightEmu(XSSFSheet sheet, int rowIndex) {
    XSSFRow row = sheet.getRow(rowIndex);
    float heightPt = row == null ? sheet.getDefaultRowHeightInPoints() : row.getHeightInPoints();
    // 磅转EMU:72磅=1英寸=914400EMU
    return (long) (heightPt * 914400.0 / 72);
}

注意事项

  • 该方案直接固定图片的展示尺寸,不需要依赖POI读取EMF原始维度的能力,所有格式的图片都可以用这个方案固定尺寸
  • 如果需要按图片原始比例缩放,可以提前用第三方工具(如batik)读取EMF的原始宽高比,再按比例换算目标尺寸即可
  • 代码里已经兼容了默认行高、默认列宽的场景,不需要提前给对应行列设置固定宽高

内容的提问来源于stack exchange,提问作者dodobird

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.14 13:15:04