2

There is a question which solves how to add a background image for an Excel Comment in versions previous to 2007 (format .xsl), with HSSF Apache POI.

apache poi insert comment with picture

But looking the doc, I cannot locate an equivalent method for XSSF Apache POI (.xslx formats).

It seems this key method was removed when moving from HSSF to XSSF:

HSSFComment        comment;
...
comment.setBackgroundImage(picIndex); // set picture as background image
Olaf Kock
  • 46,930
  • 8
  • 59
  • 90
Strings
  • 23
  • 4

2 Answers2

2

It is not supported using a method of XSSFComment. But if one knows what needs to be created, then it is not impossible.

First we need creating a default comment as shown in Quick-Quide CellComments.

Then we need adding picture data to this workbook as shown in Quick-Guide Images. We need the XSSFPictureData for adding references later.

Then we need getting the VML drawing. XSSFComments are stored in VML drawings and not in default XSSFDrawings. This is not public provided, so we need using reflection to do so.

Now we need setting the relation to the picture data in VML drawing.

At last we need getting the comment shape out of the VML drawing to set the fill of that comment shape to show the picture. There are no high level methods for this. So we need using methods of low level com.microsoft.schemas.vml.* classes.

The following example needs the full jar of all of the schemas ooxml-schemas-1.4.jar as mentioned in FAQ. It is tested using apache poi 4.1.1.

Complete example:

import java.io.FileOutputStream;
import java.io.FileInputStream;
import java.io.InputStream;
import org.apache.poi.xssf.usermodel.*;
import org.apache.poi.util.IOUtils;

class CreateXSSFCommentWithPicture {

 public static void main(String[] args) throws Exception {

  try (XSSFWorkbook workbook = new XSSFWorkbook(); 
       FileOutputStream fileout = new FileOutputStream("Excel.xlsx") ) {

   // First we create a default XSSFComment:

   XSSFCreationHelper factory = workbook.getCreationHelper();

   XSSFSheet sheet = workbook.createSheet("Sheet");
   XSSFRow row = sheet.createRow(3);
   XSSFCell cell = row.createCell(5);
   cell.setCellValue("F4");

   XSSFDrawing drawing = sheet.createDrawingPatriarch();

   XSSFClientAnchor anchor = factory.createClientAnchor();
   anchor.setCol1(cell.getColumnIndex());
   anchor.setCol2(cell.getColumnIndex()+2);
   anchor.setRow1(row.getRowNum());
   anchor.setRow2(row.getRowNum()+5);

   XSSFComment comment = drawing.createCellComment(anchor);
   XSSFRichTextString str = factory.createRichTextString("Hello, World!");
   comment.setString(str);
   comment.setAuthor("Apache POI");

   // assign the comment to the cell
   cell.setCellComment(comment);


   // Now we put the image as fill of the comment's shape:

   // add picture data to this workbook
   InputStream is = new FileInputStream("samplePict.jpeg");
   byte[] bytes = IOUtils.toByteArray(is);
   int pictureIdx = workbook.addPicture(bytes, XSSFWorkbook.PICTURE_TYPE_JPEG);
   is.close();
   // get picture data
   XSSFPictureData pictureData = workbook.getAllPictures().get(pictureIdx);

   // get VML drawing
   java.lang.reflect.Method getVMLDrawing = XSSFSheet.class.getDeclaredMethod("getVMLDrawing", boolean.class);
   getVMLDrawing.setAccessible(true);
   XSSFVMLDrawing vml = (XSSFVMLDrawing)getVMLDrawing.invoke(sheet, true);

   // set relation to the picture data in VML drawing
   org.apache.poi.ooxml.POIXMLDocumentPart.RelationPart rp = vml.addRelation(null, XSSFRelation.IMAGES, pictureData);

   // get comment shape
   com.microsoft.schemas.vml.CTShape commentShape = vml.findCommentShape(cell.getRow().getRowNum(), cell.getColumnIndex());
   // get fill of comment shape
   com.microsoft.schemas.vml.CTFill fill = commentShape.getFillArray(0);
   // already set color needs to be color2 now
   fill.setColor2(fill.getColor());
   fill.unsetColor();
   // set relation Id of the picture
   fill.setRelid(rp.getRelationship().getId());
   // set some other properties
   fill.setTitle("samplePict");
   fill.setRecolor(com.microsoft.schemas.vml.STTrueFalse.T);
   fill.setRotate(com.microsoft.schemas.vml.STTrueFalse.T);
   fill.setType(com.microsoft.schemas.vml.STFillType.FRAME);

   workbook.write(fileout);
  }

 }
}
Axel Richter
  • 56,077
  • 6
  • 60
  • 87
  • Which version of poi-ooxml-schemas are you using? The image is not still rendered even if the code has sense to me (I suspected it was related to 'microsoft vml'). The statis import STFillType enum is not available under my package. Tested with version 4.0.0 and 4.1.1 – Strings Jan 14 '20 at 08:03
  • Ok, the trick is to use ooxml-schemas-1.4.jar which contains all schemas and explictly exclude in pom any transitive dependency of 'poi-ooxml-schemas' jar. – Strings Jan 14 '20 at 10:36
  • @Strings: Yes, you are correct. I forgot mentioning that. Now I have supplemented my answer accordingly. – Axel Richter Jan 14 '20 at 13:34
0

According to this, adding image to comments was only added for HSSF.

I suppose you'll have to use another approach, like in apache poi guide.

Max
  • 915
  • 10
  • 28