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

Apache POI中Worksheet图片缩放功能失效问题排查

Apache POI 5.2.3 插入XLSM图片缩放异常问题解决

问题原因

  • Apache POI的Picture.resize()方法是基于图片原始DPI和Excel默认的96DPI来换算显示尺寸的。Pexels下载的图片大多是300DPI的高分辨率图,当你调用resize(scale)时,POI会按原始DPI计算实际显示大小,相当于额外做了一次反向缩放(300/96≈3.125倍),比如你设0.5的缩放比例,实际显示效果是0.5*(96/300)=0.16倍,自然会变成小点。
  • 少数情况是图片插入时未正确绑定工作表的绘图锚点,但核心问题还是DPI不匹配。

正确缩放方案

方案1:直接设置图片目标宽高(推荐)

跳过resize(),直接用Picture.setWidth()和Picture.setHeight()指定Excel中显示的像素尺寸,单位是EMU,可以用Units.pixelToEMU()做转换。

示例代码:

import org.apache.poi.ss.usermodel.*;
import org.apache.poi.util.Units;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class XLSMImageResize {
    public static void main(String[] args) throws IOException {
        // 创建默认字体为Calibri 11px的XLSM工作簿
        Workbook workbook = new XSSFWorkbook();
        Font defaultFont = workbook.createFont();
        defaultFont.setFontName("Calibri");
        defaultFont.setFontHeightInPoints((short)11);
        CellStyle defaultStyle = workbook.createCellStyle();
        defaultStyle.setFont(defaultFont);
        workbook.setCellStyleAt(0, defaultStyle);

        Sheet sheet = workbook.createSheet("ImageSheet");

        // 读取本地图片(已从Pexels下载好)
        String imgPath = "your-image-path.jpg";
        byte[] imgBytes = new byte[(int) new java.io.File(imgPath).length()];
        try (FileInputStream fis = new FileInputStream(imgPath)) {
            fis.read(imgBytes);
        }

        // 插入图片并设置尺寸
        int pictureIdx = workbook.addPicture(imgBytes, Workbook.PICTURE_TYPE_JPEG);
        CreationHelper helper = workbook.getCreationHelper();
        Drawing<?> drawing = sheet.createDrawingPatriarch();
        ClientAnchor anchor = helper.createClientAnchor();
        
        // 锚定到A1单元格
        anchor.setCol1(0);
        anchor.setRow1(0);

        Picture pict = drawing.createPicture(anchor, pictureIdx);
        
        // 设置目标显示尺寸:400x300像素
        int targetWidthPx = 400;
        int targetHeightPx = 300;
        pict.setWidth(Units.pixelToEMU(targetWidthPx));
        pict.setHeight(Units.pixelToEMU(targetHeightPx));

        // 保存工作簿
        try (FileOutputStream fos = new FileOutputStream("output.xlsm")) {
            workbook.write(fos);
        }
        workbook.close();
    }
}

方案2:修正图片DPI后调用resize()

如果一定要用resize()方法,先把图片的原始DPI改成96(Excel默认值),再调用缩放方法。可以用ImageIO处理图片DPI:

示例代码片段:

import javax.imageio.ImageIO;
import javax.imageio.ImageWriteParam;
import javax.imageio.ImageWriter;
import javax.imageio.metadata.IIOMetadata;
import javax.imageio.metadata.IIOMetadataNode;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileOutputStream;

// 读取图片并修改DPI为96
BufferedImage img = ImageIO.read(new File(imgPath));
ImageWriter writer = ImageIO.getImageWritersByFormatName("jpeg").next();
ImageWriteParam param = writer.getDefaultWriteParam();

IIOMetadata metadata = writer.getDefaultImageMetadata(new javax.imageio.ImageTypeSpecifier(img), param);
IIOMetadataNode root = (IIOMetadataNode) metadata.getAsTree("javax_imageio_jpeg_image_1.0");
IIOMetadataNode jpegVariety = (IIOMetadataNode) root.getElementsByTagName("JPEGvariety").item(0);
IIOMetadataNode markerSequence = (IIOMetadataNode) jpegVariety.getElementsByTagName("markerSequence").item(0);

IIOMetadataNode dpiNode = new IIOMetadataNode("appJFIF");
dpiNode.setAttribute("Xdensity", "96");
dpiNode.setAttribute("Ydensity", "96");
dpiNode.setAttribute("units", "1"); // 1代表像素/英寸
markerSequence.appendChild(dpiNode);

// 写入临时文件
File tempImg = File.createTempFile("temp", ".jpg");
try (FileOutputStream fos = new FileOutputStream(tempImg)) {
    writer.setOutput(ImageIO.createImageOutputStream(fos));
    writer.write(metadata, new javax.imageio.IIOImage(img, null, metadata), param);
}

// 后续读取临时文件插入图片,再调用resize(0.5)就能正常缩放

注意事项

  • 针对XLSM(XSSF格式),使用通用的Drawing和ClientAnchor即可,无需特意强转成XSSF专属类。
  • 可以配合sheet.setColumnWidth()和sheet.setRowHeight()调整单元格大小,让图片排版更合理。

内容的提问来源于stack exchange,提问作者Michał Mańkowski

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 08:10:24