如何使用 POI 将 excel 中的一张图片替换为另一张图片

how to replace an image with another image in excel using POI

我需要帮助使用 Apache POI 将 excel sheet 中的一张图片替换为另一张图片。

int myPictureId=0;
List<XSSFShape> pictures = drawing.getShapes();
for(XSSFShape shape : pictures) {
    XSSFPicture picture = (XSSFPicture)shape; //Get picture
    byte[] data = picture.getPictureData().getData(); //Get picture data
    XSSFClientAnchor anchor = picture.getClientAnchor(); //Get anchor
    ByteArrayInputStream byteInput = new ByteArrayInputStream(data);
    BufferedImage image = ImageIO.read(byteInput);
    data = getByteArrayFromImage(image, 400, data, picture.getPictureData().suggestFileExtension());
    myPictureId = workbook.addPicture(new ByteArrayInputStream(data), Workbook.PICTURE_TYPE_PNG);
    picture = drawing.createPicture(anchor, myPictureId);
}

我正在使用 getByteArrayFromImage 方法来压缩我的图像并将原始图像替换为压缩后的图像。我还尝试使用 XSSFClientAnchor 将压缩图像附加到原始图像,但 excel 将原始图像与压缩图像重叠。

不清楚getByteArrayFromImage在做什么。但它似乎只改变了源 BufferedImage 的数据字节上的某些内容,源 BufferedImage 从源 XSSFPictureData 的数据字节和 returns 然后更改了数据字节。

如果这个新的数据字节应该替换源XSSFPictureData中的源数据字节,那么下面的方法可以做到这一点:

 void replacePictureData(XSSFPictureData source, byte[] data) {
  try ( ByteArrayInputStream in = new ByteArrayInputStream(data); 
        OutputStream out = source.getPackagePart().getOutputStream();
       ) {
   byte[] buffer = new byte[2048];
   int length;
   while ((length = in.read(buffer)) > 0) {
    out.write(buffer, 0, length);
   }
  } catch (Exception ex) {
   ex.printStackTrace();  
  }
 }

XSSFPictureData*.xlsx ZIP 压缩包的一部分,因此它提供了 getOutputStream 方法。

下面完整的例子展示了它的整体。我的 getByteArrayFromImage 将文本“CHANGED”写入 Excel 文件中的图片。

import org.apache.poi.ss.usermodel.WorkbookFactory;
import org.apache.poi.xssf.usermodel.*;

import java.io.*;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;

import java.util.List;

class ExcelReplacePictures {
    
 static void replacePictureData(XSSFPictureData source, byte[] data) {
  try ( ByteArrayInputStream in = new ByteArrayInputStream(data); 
        OutputStream out = source.getPackagePart().getOutputStream();
       ) {
   byte[] buffer = new byte[2048];
   int length;
   while ((length = in.read(buffer)) > 0) {
    out.write(buffer, 0, length);
   }
  } catch (Exception ex) {
   ex.printStackTrace();  
  }
 }

 static byte[] getByteArrayFromImage(BufferedImage image, Dimension dimension, byte[] data, String type) {
  try {
   Graphics g = image.getGraphics();  
   g.setColor(Color.red);
   g.setFont(new Font("Serif", Font.BOLD, 40));
   String s = "CHANGED";
   FontMetrics fm = g.getFontMetrics();
   int x = image.getWidth() / 2 - fm.stringWidth(s) / 2;
   int y = image.getHeight() / 2 + fm.getHeight() / 2;
   g.drawString(s, x, y);
   g.dispose();
   ByteArrayOutputStream baos = new ByteArrayOutputStream();
   ImageIO.write(image, type, baos);
   data = baos.toByteArray(); 
  } catch (Exception ex) {
   ex.printStackTrace();  
  }  
  return data;
 }
 
 public static void main(String[] args) throws Exception {

  try (XSSFWorkbook workbook = (XSSFWorkbook)WorkbookFactory.create(new FileInputStream("./ExcelWithPictures.xlsx"));
       FileOutputStream out = new FileOutputStream("./ExcelWithPicturesNew.xlsx");
      ) {

   for (int i = 0; i < workbook.getNumberOfSheets(); i++) {
    XSSFSheet sheet = workbook.getSheetAt(i);   
    XSSFDrawing drawing = sheet.getDrawingPatriarch();
    List<XSSFShape> shapes = drawing.getShapes();
    for (XSSFShape shape : shapes) {
     if (shape instanceof XSSFPicture) {
      XSSFPicture picture = (XSSFPicture)shape; 
      XSSFPictureData pictureData =  picture.getPictureData();
      byte[] data = pictureData.getData();
      ByteArrayInputStream byteInput = new ByteArrayInputStream(data);
      BufferedImage image = ImageIO.read(byteInput);
      data = getByteArrayFromImage(image, picture.getImageDimension(), data, pictureData.suggestFileExtension());
      replacePictureData(pictureData, data);
     }
    } 
   } 
   workbook.write(out);
  } catch (Exception ex) {
    ex.printStackTrace();  
  } 
 }
}