Home » excel » java – In Apache POI 3.9 using autosizeColumn the image present on the same column getting stretched

java – In Apache POI 3.9 using autosizeColumn the image present on the same column getting stretched

Posted by: admin April 23, 2020 Leave a comment

Questions:

I have an image and some text below the image in an excel sheet. when i am applying autoSizeColumn() to the column where text present the image is also getting streched .
i am also setting the anchortype to 2 but this is not protecting the image to resize.
I am posting some sample code here.

public static void main(String[] args) {
    try{
    XSSFWorkbook book = new XSSFWorkbook();
    XSSFSheet sheet = book.createSheet("Test Sheet");
     InputStream is = new          FileInputStream("D:\RPM_Eclipse_Workspaces\B6.9\00POI\Chrysanthemum.jpg");
        byte[] bytes = IOUtils.toByteArray(is);
        int pictureIdx = book.addPicture(bytes, Workbook.PICTURE_TYPE_PNG);
        Drawing drawing = sheet.createDrawingPatriarch();
        ClientAnchor anchor = new XSSFClientAnchor(0, 0, 1023, 255, 2,2,10,10);

        //Image should not get Resized while doing Autosize
        anchor.setAnchorType(ClientAnchor.DONT_MOVE_AND_RESIZE);
        Picture pict = drawing.createPicture(anchor, pictureIdx);

        XSSFRow row = sheet.createRow(12);
        for(int i = 2 ; i < 11 ; i++){
            XSSFCell cell = row.createCell(i);
            cell.setCellValue("oval (although anchor's type is set to MOVE_DONT_RESIZE ). ... But the one way to ");

        }
       sheet.autoSizeColumn(2);
    book.write(new FileOutputStream(new File("D:\auto.xlsx")));
    System.out.println("=== DONE ===");
    }catch (Exception e){

    }
}
How to&Answers:

POI uses TwoCellAnchors for adding pictures … so with a bit of nasty reflections, you can add a Picture with a OneCellAnchor

In the example the drawing.createAnchor(10, 10, 110, 110, 2, 2, 0, 0) is used to position the image 10×10 from the top left corner of the cell(2,2) and scale the picture to 100×100 pixels, i.e. 110-10.

(tested with Libre Office 4.0, Excel Viewer 2010)

import java.io.*;
import java.lang.reflect.*;

import org.apache.poi.openxml4j.opc.PackageRelationship;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.util.IOUtils;
import org.apache.poi.xssf.usermodel.*;
import org.openxmlformats.schemas.drawingml.x2006.main.CTPositiveSize2D;
import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.*;

public class Automation {

    public static void main(String[] args) throws Exception {
        XSSFWorkbook book = new XSSFWorkbook();
        XSSFSheet sheet = book.createSheet("Test Sheet");
        InputStream is = new FileInputStream("src/test/resources/smiley.jpg");
        byte[] bytes = IOUtils.toByteArray(is);
        int pictureIdx = book.addPicture(bytes, Workbook.PICTURE_TYPE_PNG);
        XSSFDrawing drawing = sheet.createDrawingPatriarch();

        XSSFClientAnchor anchor = drawing.createAnchor(10, 10, 110, 110, 2, 2, 0, 0);

        createPicture(anchor, pictureIdx, drawing);

        XSSFRow row = sheet.createRow(12);
        for (int i = 2; i < 11; i++) {
            XSSFCell cell = row.createCell(i);
            cell.setCellValue("oval (although anchor's type is set to MOVE_DONT_RESIZE ). ... But the one way to ");

        }
        sheet.autoSizeColumn(2);
        book.write(new FileOutputStream(new File("auto.xlsx")));
    }

    public static XSSFPicture createPicture(XSSFClientAnchor anchor, int pictureIndex, XSSFDrawing drawing)
    throws Exception
    {
        Method m = XSSFDrawing.class.getDeclaredMethod("addPictureReference", int.class);
        m.setAccessible(true);
        PackageRelationship rel = (PackageRelationship)m.invoke(drawing, (Integer)pictureIndex);

        long shapeId = 1000+drawing.getCTDrawing().sizeOfOneCellAnchorArray();
        CTOneCellAnchor ctAnchor = createOneCellAnchor(drawing, anchor);
        CTPicture ctShape = ctAnchor.addNewPic();

        m = XSSFPicture.class.getDeclaredMethod("prototype");
        m.setAccessible(true);
        CTPicture ctp = (CTPicture)m.invoke(null);
        ctShape.set(ctp);
        ctShape.getNvPicPr().getCNvPr().setId(shapeId);

        Constructor<XSSFPicture> picCon = XSSFPicture.class
            .getDeclaredConstructor(XSSFDrawing.class, CTPicture.class);
        picCon.setAccessible(true);

        XSSFPicture shape = picCon.newInstance(drawing, ctShape);
        Field f = XSSFShape.class.getDeclaredField("anchor");
        f.setAccessible(true);
        f.set(shape, anchor);

        m = XSSFPicture.class.getDeclaredMethod("setPictureReference", PackageRelationship.class);
        m.setAccessible(true);
        m.invoke(shape, rel);
        return shape;
    }

    public static CTOneCellAnchor createOneCellAnchor(XSSFDrawing drawing, XSSFClientAnchor anchor) {
        final int pixel2emu = 12700;
        CTOneCellAnchor ctAnchor = drawing.getCTDrawing().addNewOneCellAnchor();

        long cx = (anchor.getTo().getRowOff()-anchor.getFrom().getRowOff())*pixel2emu;
        long cy = (anchor.getTo().getColOff()-anchor.getFrom().getColOff())*pixel2emu;
        CTPositiveSize2D size = CTPositiveSize2D.Factory.newInstance();
        size.setCx(cx);
        size.setCy(cy);
        ctAnchor.setExt(size);

        ctAnchor.setFrom(anchor.getFrom());
        CTMarker m = ctAnchor.getFrom();
        m.setColOff(m.getColOff()*pixel2emu);
        m.setRowOff(m.getRowOff()*pixel2emu);
        ctAnchor.addNewClientData();
        try {
            Method mt = XSSFClientAnchor.class.getDeclaredMethod("setFrom", CTMarker.class);
            mt.setAccessible(true);
            mt.invoke(anchor, ctAnchor.getFrom());
        } catch (Exception e) {
            throw new RuntimeException("handle me", e);
        }

        return ctAnchor;
    }
}

Answer:

In picture.resize () method, to calculate the original height of the image, it use the row.getHeight value.
The problem is, the row height value !
Depending on the contents of the cell, the row height is increased automatically, but you cannot obtain the increased height value by row.getHeight() method.
So, you need to set the height of row using row.setHeigth (height) manually.
then you can be obtained for the normal image size and the picture.resize () method will work properly.