Excel遍历图片 适应单元格大小并居中

我有一个excel中含有多张照片,我想要按照将里面的图片全部适应单元格大小并居中处理 ,有什么好的方法吗? 最好性能上是比较好

@xiaoman,

请参阅以下示例代码来完成您的任务。请参考它,然后根据您的需要编写/更新您的代码。
例如,
示例代码:

//Open the Excel file
Workbook workbook = new Workbook("d:\\files\\Book1.xlsx");
Worksheet worksheet = workbook.getWorksheets().get(0);

//Get all the images in the worksheet
PictureCollection pictures = worksheet.getPictures();

for (int i = 0; i < pictures.getCount(); i++)
{
            Picture picture = pictures.get(i);

            //Get the cell containing the picture
            int row = picture.getUpperLeftRow();
            int column = picture.getUpperLeftColumn();
            Cell cell = worksheet.getCells().get(row, column);

            
            double cellWidth = worksheet.getCells().getColumnWidthPixel(column);
            double cellHeight = worksheet.getCells().getRowHeightPixel(row);

            //Get the original dimensions of the picture
            double picWidth = picture.getWidth();
            double picHeight = picture.getHeight();

            //Calculate the scale factors to fit the image within the cell
            double scaleX = cellWidth / picWidth;
            double scaleY = cellHeight / picHeight;

            //Choose the smaller scale to maintain the aspect ratio
            double scale = Math.min(scaleX, scaleY);

            //Resize the picture
            picture.setWidth((int)(picWidth * scale));
            picture.setHeight((int)(picHeight * scale));

            //Center the image within the cell by adjusting the left and top offsets
            int leftOffset = (int)((cellWidth - picture.getWidth()) / 2);
            int topOffset = (int)((cellHeight - picture.getHeight()) / 2);
            picture.setLeft(leftOffset);
            picture.setTop(topOffset);
}

//Save the updated workbook
workbook.save("d:\\files\\out1.xlsx");

希望这会有所帮助。

@xiaoman
你可以使用单元格嵌入图片来实现需求,请查看附件。result.zip (4.1 MB)

样例代码如下:

//Open the Excel file
Workbook workbook = new Workbook(filePath + "sample.xlsx");
Worksheet worksheet = workbook.getWorksheets().get(0);

//Get all the images in the worksheet
PictureCollection pictures = worksheet.getPictures();

for (int i = 0; i < pictures.getCount(); i++)
{
            Picture picture = pictures.get(i);

            //Get the cell containing the picture
            int row = picture.getUpperLeftRow();
            int column = picture.getUpperLeftColumn();
            Cell cell = worksheet.getCells().get(row, column);

            Style style = cell.getStyle();
            style.setHorizontalAlignment(TextAlignmentType.CENTER);
            style.setVerticalAlignment(TextAlignmentType.CENTER);
            
            cell.setEmbeddedImage(picture.getData());
            cell.setStyle(style);
}
pictures.clear();

//Save the updated workbook
workbook.save(filePath + "out_java.xlsx");

image.jpg (86.2 KB)

好像并不行

@xiaoman
请提供你的样例文件,你可以压缩成zip格式并上传到这里。我们很快就会检查。另外,请注意,单元格嵌入图片功能是高版本Excel才支持的,你需要使用office 365进行查看。

@xiaoman ,

放在单元格中的图片(Placed in Cell Picture)是Microsoft Excel的新的特性,如果你使用的是WPS或者低版本的Microsoft Excel,此特性可能没有支持。

你可以尝试 @amjad.sahi 的解决方案:

你好 感谢你们的解答! 现在才有时间回复, 这个问题已经解决了,现在遇到新的问题,我研究了一下贵方的SDK,好像不支持跨单格/合并单元格的图片插入居中., 望解答 谢谢!

@xiaoman,

MS Excel 中没有特定选项可将图像插入到正常或合并的单元格中,从而使它们集中起来。您可以使用代码中的 Aspose.Cells for Java API 轻松完成此操作。请在压缩档案中找到附加的模板 Excel 文件,其中包含一个工作表,其中包含一些合并单元格和宽度和高度较大的正常单元格。我将选择两个单元格(D2 和 D8)来测试将图片插入单元格。D2 是合并单元格,D8 是正常单元格。另请查看我将插入单元格的测试图片。输出 Excel 文件也存在于附加档案中。请尝试参考带有模板 Excel 文件的代码片段,并根据需要编写/更新代码。

// Load the workbook and worksheet
Workbook workbook = new Workbook("d:\\files\\Bk_test1.xlsx");
Worksheet worksheet = workbook.getWorksheets().get(0);

Cell destCell = worksheet.getCells().get("D2");//merged cell
//Cell destCell = worksheet.getCells().get("D8");//normal cell

double columnWidth = worksheet.getCells().getColumnWidthInch(destCell.getColumn());
double rowHeight = worksheet.getCells().getRowHeightInch(destCell.getRow());
if(destCell.isMerged())
{
    Range range = destCell.getMergedRange();
    if (range != null) {
        //Calculate total width of merged cells
        for (int c = range.getColumnCount() - 1; c > 0; c--) {
            columnWidth += worksheet.getCells().getColumnWidthInch(range.getFirstColumn() + c);
        }
        //Calculate total height of merged cells
        for (int r = range.getRowCount() - 1; r > 0; r--) {
            rowHeight += worksheet.getCells().getRowHeightInch(range.getFirstRow() + r);
        }
    }
}
// Load the image
String imagePath = "d:\\files\\pict1.png"; // Provide your image path
File imageFile = new File(imagePath);
if (!imageFile.exists()) {
   System.out.println("Image file not found.");
   return;
}

// Add the picture
int pictureIndex = worksheet.getPictures().add(destCell.getRow(), destCell.getColumn(), imagePath);
Picture picture = worksheet.getPictures().get(pictureIndex);

double imageWidthInch = picture.getWidthInch();  // Adjust according to the image's width
double imageHeightInch = picture.getHeightInch(); // Adjust according to the image's height

double xOffset = (columnWidth - imageWidthInch) / 2;
double yOffset = (rowHeight - imageHeightInch) / 2;

picture.setLeftInch(xOffset);
picture.setTopInch(yOffset);
picture.setWidthInch(imageWidthInch);
picture.setHeightInch(imageHeightInch);

// Save the workbook
workbook.save("d:\\files\\CenteredImageInMergedCell.xlsx");

files1.zip (680.3 KB)

希望这有帮助。

两个问题, 图片自适应居中,如果单元格/合并单元格比较大,图片容易拉伸变形 没有真正的等比例缩放! 第二个,设置了4张图片,生成的文件只能看到两张! 请帮忙看看 谢谢!

@Test
public void testApose() throws Exception {
Workbook workbook = new Workbook(“/Desktop/图片/Bk_test1.xlsx”);
Worksheet worksheet = workbook.getWorksheets().get(0);

    // Load the image
    String imagePath = "/Desktop/图片/原始图.png";
    //String imagePath2 = "/Users/robert/Desktop/图片/橙4063.jpg";

    writeImageApose(worksheet,imagePath,"A3");//merge
    writeImageApose(worksheet,imagePath,"B2");//normal
    writeImageApose(worksheet,imagePath,"A6");//normal
    writeImageApose(worksheet,imagePath,"D2");// merge

    workbook.save("/Desktop/CenteredImageInMergedCell-02.xlsx");
}


public static void writeImageApose(Worksheet worksheet,String imagePath, String cell) throws Exception {

    Cell destCell = worksheet.getCells().get(cell);
    double columnWidth = worksheet.getCells().getColumnWidthInch(destCell.getColumn());
    double rowHeight = worksheet.getCells().getRowHeightInch(destCell.getRow());
    if (destCell.isMerged()) {
        Range range = destCell.getMergedRange();
        if (range != null) {
            for (int c = range.getColumnCount() - 1; c > 0; c--) {
                columnWidth += worksheet.getCells().getColumnWidthInch(range.getFirstColumn() + c);
            }
            for (int r = range.getRowCount() - 1; r > 0; r--) {
                rowHeight += worksheet.getCells().getRowHeightInch(range.getFirstRow() + r);
            }
        }
    }

    int pictureIndex = worksheet.getPictures().add(destCell.getRow(), destCell.getColumn(), imagePath);
    Picture picture = worksheet.getPictures().get(pictureIndex);

    double imageWidthInch = picture.getWidthInch();
    double imageHeightInch = picture.getHeightInch();

    // 图片只占cell的8成空间
    double scale = Math.min(columnWidth * 0.8 / imageWidthInch, rowHeight * 0.8 / imageHeightInch) ;
    picture.setWidthInch((int)(imageWidthInch * scale));
    picture.setHeightInch((int)(imageWidthInch * scale));

    double xOffset = (columnWidth -  picture.getWidthInch()) / 2;
    double yOffset = (rowHeight - picture.getHeightInch()) / 2;


    picture.setLeftInch(xOffset);
    picture.setTopInch(yOffset);
}

图片自适应居中.zip (507.1 KB)

图片不显示问题,我已经解决,现在的问题图片容易失真, 你可以在excel打开原始图片 然后设置跟导出的图片高度一样 会发现导出的图片的宽度和原始的宽度不一致
@Test
public void testApose(){
Workbook workbook = null;
try {
workbook = new Workbook(“/Users/robert/Desktop/图片/Bk_test1.xlsx”);
Worksheet worksheet = workbook.getWorksheets().get(0);
String path = “/Users/robert/Desktop/图片/原始图.png”;
//跨单元格居中
writeImageApose(worksheet, path,0,2,0,4);
writeImageApose(worksheet, path,0,5,0,5);
writeImageApose(worksheet, path,1,1,1,1);
writeImageApose(worksheet, path,3,1,5,4);

        workbook.save("/Users/robert/Desktop/图片/PI模板-oot-merge-18.xlsx");
    } catch (Exception e) {
        e.printStackTrace();
    }

}

@Test
public void testAposeByName() throws Exception {
    Workbook workbook = new Workbook("/Users/robert/Desktop/图片/Bk_test1.xlsx");
    Worksheet worksheet = workbook.getWorksheets().get(0);
    String imagePath = "/Users/robert/Desktop/图片/原始图.png";
    writeImageAposeByName(worksheet,imagePath,"A3");//merge
    writeImageAposeByName(worksheet,imagePath,"A6");//normal
    writeImageAposeByName(worksheet,imagePath,"B2");//normal
    writeImageAposeByName(worksheet,imagePath,"D2");// merge
    workbook.save("/Users/robert/Desktop/图片/CenteredImageInMergedCell-11.xlsx");
}


//单元格并兼容合并单元格
public static void writeImageAposeByName(Worksheet worksheet,String imagePath, String cellName) throws Exception {

    Cell destCell = worksheet.getCells().get(cellName);
    double cellWidth = worksheet.getCells().getColumnWidthPixel(destCell.getColumn());
    double rowHeight = worksheet.getCells().getRowHeightPixel(destCell.getRow());
    if (destCell.isMerged()) {
        Range range = destCell.getMergedRange();
        if (range != null) {
            for (int c = range.getColumnCount() - 1; c > 0; c--) {
                cellWidth += worksheet.getCells().getColumnWidthPixel(range.getFirstColumn() + c);
            }
            for (int r = range.getRowCount() - 1; r > 0; r--) {
                rowHeight += worksheet.getCells().getRowHeightPixel(range.getFirstRow() + r);
            }
        }
    }
    int pictureIndex = worksheet.getPictures().add(destCell.getRow(), destCell.getColumn(), imagePath);
    Picture picture = worksheet.getPictures().get(pictureIndex);

    double picWidth = picture.getWidth();
    double picHeight = picture.getHeight();
    double scaleX = cellWidth / picWidth;
    double scaleY = rowHeight / picHeight;
    double scale = Math.min(scaleX, scaleY) * 0.8;
    picture.setWidth((int)(picWidth * scale));
    picture.setHeight((int)(picHeight * scale));
    int leftOffset = (int)((cellWidth - picture.getWidth()) / 2);
    int topOffset = (int)((rowHeight - picture.getHeight()) / 2);
    picture.setLeft(leftOffset);
    picture.setTop(topOffset);
}

// 指定多个单元格
public static void writeImageApose(Worksheet worksheet,String imagePath, int col1 ,int row1,int col2 ,int row2) throws Exception {
    int picIndex = worksheet.getPictures().add(row1,col1,imagePath);
    Picture picture = worksheet.getPictures().get(picIndex);
    double cellWidth = 0;
    double cellHeight = 0;

    // 计算跨单元格的总高 总宽
    for(int i = col1; i <=col2; i++) {
        cellWidth += worksheet.getCells().getColumnWidthPixel(i);
    }
    for(int i = row1; i <=row2;i++) {
        cellHeight += worksheet.getCells().getRowHeightPixel(i);
    }
    double picWidth = picture.getWidth();
    double picHeight = picture.getHeight();
    double scaleX = cellWidth / picWidth;
    double scaleY = cellHeight / picHeight;
    double scale = Math.min(scaleX, scaleY) * 0.8;
    picture.setWidth((int)(picWidth * scale));
    picture.setHeight((int)(picHeight * scale));
    int leftOffset = (int)((cellWidth - picture.getWidth()) / 2);
    int topOffset = (int)((cellHeight - picture.getHeight()) / 2);
    picture.setLeft(leftOffset);
    picture.setTop(topOffset);
}

result.zip (756.3 KB)

@xiaoman
你愿意更详细的描述你遇到的问题吗?如果能提供截图并高亮显示错误的位置,这对我们定位问题将会很有帮助。我们很快就会检查。

image.jpg (148.4 KB)

导出后的图片的比例和原图 会有所差异! 差异大了图片可能变形

另外 我们现在用的版本太低! 想看看你们近2年的优化记录,考虑要不要采购最新的SDK,可以提供迭代优化内容的链接吗 谢谢

@xiaoman
通过使用以下样例代码在最新版本v24.12上进行测试,我们可以得到正确的结果。请查看附件。out_java.zip (251.7 KB)

Workbook workbook = null;

workbook = new Workbook(filePath + "Bk_test1.xlsx");
Worksheet worksheet = workbook.getWorksheets().get(0);
String path = filePath + "原始图.png";
//跨单元格居中
writeImageApose(worksheet, path,0,2,0,4);
writeImageApose(worksheet, path,0,5,0,5);
writeImageApose(worksheet, path,1,1,1,1);
writeImageApose(worksheet, path,3,1,5,4);

workbook.save(filePath + "out_java.xlsx");

//单元格并兼容合并单元格
public static void writeImageAposeByName(Worksheet worksheet,String imagePath, String cellName) throws Exception {

  Cell destCell = worksheet.getCells().get(cellName);
  double cellWidth = worksheet.getCells().getColumnWidthPixel(destCell.getColumn());
  double rowHeight = worksheet.getCells().getRowHeightPixel(destCell.getRow());
  if (destCell.isMerged()) {
      Range range = destCell.getMergedRange();
      if (range != null) {
          for (int c = range.getColumnCount() - 1; c > 0; c--) {
              cellWidth += worksheet.getCells().getColumnWidthPixel(range.getFirstColumn() + c);
          }
          for (int r = range.getRowCount() - 1; r > 0; r--) {
              rowHeight += worksheet.getCells().getRowHeightPixel(range.getFirstRow() + r);
          }
      }
  }
  int pictureIndex = worksheet.getPictures().add(destCell.getRow(), destCell.getColumn(), imagePath);
  Picture picture = worksheet.getPictures().get(pictureIndex);

  double picWidth = picture.getWidth();
  double picHeight = picture.getHeight();
  double scaleX = cellWidth / picWidth;
  double scaleY = rowHeight / picHeight;
  double scale = Math.min(scaleX, scaleY) * 0.8;
  picture.setWidth((int)(picWidth * scale));
  picture.setHeight((int)(picHeight * scale));
  int leftOffset = (int)((cellWidth - picture.getWidth()) / 2);
  int topOffset = (int)((rowHeight - picture.getHeight()) / 2);
  picture.setLeft(leftOffset);
  picture.setTop(topOffset);
}

//指定多个单元格
public static void writeImageApose(Worksheet worksheet,String imagePath, int col1 ,int row1,int col2 ,int row2) throws Exception {
  int picIndex = worksheet.getPictures().add(row1,col1,imagePath);
  Picture picture = worksheet.getPictures().get(picIndex);
  double cellWidth = 0;
  double cellHeight = 0;

  // 计算跨单元格的总高 总宽
  for(int i = col1; i <=col2; i++) {
      cellWidth += worksheet.getCells().getColumnWidthPixel(i);
  }
  for(int i = row1; i <=row2;i++) {
      cellHeight += worksheet.getCells().getRowHeightPixel(i);
  }
  double picWidth = picture.getWidth();
  double picHeight = picture.getHeight();
  double scaleX = cellWidth / picWidth;
  double scaleY = cellHeight / picHeight;
  double scale = Math.min(scaleX, scaleY) * 0.8;
  picture.setWidth((int)(picWidth * scale));
  picture.setHeight((int)(picHeight * scale));
  int leftOffset = (int)((cellWidth - picture.getWidth()) / 2);
  int topOffset = (int)((cellHeight - picture.getHeight()) / 2);
  picture.setLeft(leftOffset);
  picture.setTop(topOffset);
}

我们建议您尝试使用我们的最新版本:
Aspose.Cells for Java v24.12.
另外,请不要使用主题字体,如果设置了 Excel 主题字体,Excel 将根据当前语言环境自动在不同字体之间切换。关于主题字体,请查看相关文档。

请检查一下你的Excel显示的默认字体是什么?默认字体是否安装了?默认字体会影响列宽和行高的数据测量。如果你有任何疑问,请随时联系我们。

好的 我先试试 有问题再请教您 谢谢!

@xiaoman
感谢你的反馈。不客气。如果你有任何疑问,请随时联系我们。

你好 想问一下 这三个方法返回的数据 要怎么转换 我现在有一段代码转换以后 好像图片居中就不对了
org.apache.poi.ss.usermodel.Sheet.getRow(i).getHeightInPoints()
com.aspose.cells.getCells().getRowHeight(i)
com.aspose.cells.getCells().getRowHeightPixel
//自动调整行高
if (autoFitRows != null && autoFitRows.size() == MIN_PRODUCT_CELLS && autoFitRows.get(0) != -1 && autoFitRows.get(1) != -1) {
aposeSheet.autoFitRows(autoFitRows.get(0), autoFitRows.get(1));
}
Sheet apacheSheet = excelWorker.get_sheet();
for (int i = autoFitRows.get(0); i <= autoFitRows.get(1); i++) {
if (apacheSheet.getRow(i) == null) {
continue;
}
double rowHeightBefore = apacheSheet.getRow(i).getHeightInPoints();
double rowHeightAfter = aposeSheet.getCells().getRowHeight(i);
//调整后的行高和原行高做比对 取最大的行高
aposeSheet.getCells().setRowHeight(i, Math.max(rowHeightBefore,rowHeightAfter));
}

@xiaoman,

您能否分享一个独立的可运行 Java 代码/程序示例以及示例文件(Excel 文件、图像文件等)以便在我们这边重现该问题,我们会尽快检查。

好 我写个单元测试 这个是在业务代码里面的! 另外, 昨天你提到让我使用最新的24年的SDK,目前我们公司用不了,我们的是2022年的,能否给个临时的让我先测试,如果效果好,我们会重新采购贵方的最新SDK !

@xiaoman,

是的,我们建议您尝试升级到最新版本和 API 集。然后使用最新版本的 Aspose.Cells for Java 尝试您的场景/案例。要测试您的场景/案例,您可以根据您的要求申请 30 天的临时许可证。请参阅有关如何获取临时许可证的页面。
https://purchase.aspose.com/temporary-license/