Home > Back-end >  how to replace an image with another image in excel using POI
how to replace an image with another image in excel using POI

Time:03-04

I need help replacing an image with another image in an excel sheet using Apache POI.

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

I am using the getByteArrayFromImage method to compress my image and replace the original image with the compressed one. I also tried using XSSFClientAnchor to attach the compressed image to the original image but excel is overlapping the original image with the compressed image.

CodePudding user response:

Not clear what getByteArrayFromImage is doing. But as it seems it only changes something on the data bytes of the source BufferedImage got from the data bytes from source XSSFPictureData and returns the changed data bytes then.

If this new data bytes shall be the replacement of the source data bytes from source XSSFPictureData, then following method can do this:

 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 is a package part of the *.xlsx ZIP archive and so it provides a getOutputStream method.

The following complete example shows it in whole. My getByteArrayFromImage writes the text "CHANGED" onto the pictures in the Excel file.

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();  
  } 
 }
}
  • Related