0

I'm trying to copy an image from a XLS to a XLSX, using Apache Poi 4.1.2. I'm not able to calculate the right value for dy2.

My code:

package poisamples;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Iterator;

import org.apache.poi.ss.usermodel.ClientAnchor.AnchorType;
import org.apache.poi.hssf.usermodel.HSSFClientAnchor;
import org.apache.poi.hssf.usermodel.HSSFPatriarch;
import org.apache.poi.hssf.usermodel.HSSFPicture;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;

import org.apache.poi.util.Units;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.ClientAnchor;
import org.apache.poi.ss.usermodel.CreationHelper;
import org.apache.poi.ss.usermodel.Drawing;
import org.apache.poi.ss.usermodel.Picture;
import org.apache.poi.ss.usermodel.PictureData;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

public class HSSFtoXSSF {

  private static HSSFWorkbook createXLS() {
    String imageFile = "test.png";
    String outputFile = "oldFile.xls";
    HSSFWorkbook workbook = new HSSFWorkbook();
    HSSFSheet sheet = workbook.createSheet("Image");
    HSSFClientAnchor anchor = new HSSFClientAnchor(27,75,11,174,(short)0, (short)0, (short)7, (short)3);

    sheet.setColumnWidth(0, 6000);

    anchor.setAnchorType(AnchorType.DONT_MOVE_AND_RESIZE);
    try {
      int index = sheet.getWorkbook().addPicture(imageToBytes(imageFile), HSSFWorkbook.PICTURE_TYPE_PNG);
      HSSFPatriarch patriarch = sheet.createDrawingPatriarch();
      HSSFPicture picture = patriarch.createPicture(anchor, index);
      FileOutputStream fos = new FileOutputStream(outputFile);
      workbook.write(fos);
      fos.close();
    }
    catch (IOException ioe) {
      System.out.println("Error reading image");
    }
    return workbook;
  }

  private static byte[] imageToBytes(String imageFilename) throws IOException {
    File imageFile;
    FileInputStream fis = null;
    ByteArrayOutputStream bos;
    int read;
    try {
      imageFile = new File(imageFilename);
      fis = new FileInputStream(imageFile);
      bos = new ByteArrayOutputStream();
      while ((read = fis.read()) != -1) {
        bos.write(read);
      }
      return (bos.toByteArray());
    }
    finally {
      if (fis != null) {
        try {
          fis.close();
          fis = null;
        }
        catch (IOException ioEx) {
          // Nothing to do here
        }
      }
    }
  }

  private static void transferImages (HSSFSheet sheet, XSSFSheet newSheet) {
    if ( sheet.getDrawingPatriarch() == null) {
      sheet.createDrawingPatriarch();
    }
    Drawing<?> drawing = sheet.getDrawingPatriarch();
    Iterator<?> it = drawing.iterator();
    while (it.hasNext()) {
      Object shape = it.next();
      if (shape instanceof Picture) {
        copyImage((Picture)shape, sheet, newSheet);
      }
    }
  }

  private static void copyImage(Picture shape, HSSFSheet oldSheet, XSSFSheet newSheet) {
    PictureData pictureData = shape.getPictureData();
    ClientAnchor oldAnchor = (ClientAnchor) shape.getAnchor();

    int col1 = oldAnchor.getCol1();
    int col2 = oldAnchor.getCol2();
    int row1 = oldAnchor.getRow1();
    int row2 = oldAnchor.getRow2();

    int x1 = oldAnchor.getDx1();
    int x2 = oldAnchor.getDx2();
    int y1 = oldAnchor.getDy1();
    int y2 = oldAnchor.getDy2();
    int DEFAULT_COL_WIDTH = 10 * 256;
    float DEFAULT_ROW_HEIGHT = 12.75f;

    // Calculate row height
    Row row = oldSheet.getRow(row1);
    float rowHeightInPoints1 = (row!=null)?row.getHeightInPoints():DEFAULT_ROW_HEIGHT;
    float rowHeightInPixels1 = rowHeightInPoints1 * Units.PIXEL_DPI / Units.POINT_DPI;
    row = oldSheet.getRow(row2);
    float rowHeightInPoints2 = (row!=null)?row.getHeightInPoints():DEFAULT_ROW_HEIGHT;
    float rowHeightInPixels2 = rowHeightInPoints2 * Units.PIXEL_DPI / Units.POINT_DPI;

    // Calculate column width
    int colwidth1 = oldSheet.getColumnWidth(col1);
    int colwidth2 = oldSheet.getColumnWidth(col2);

    y1 = (int)Math.round(y1 / Units.PIXEL_DPI * Units.POINT_DPI / 14.75 / DEFAULT_ROW_HEIGHT * rowHeightInPixels1);
    x1 = (int)Math.round((x1 / (Units.DEFAULT_CHARACTER_WIDTH * 256f) / 14.75) / DEFAULT_COL_WIDTH * colwidth1);
    y2 = (int)Math.round(y2 / Units.PIXEL_DPI * Units.POINT_DPI / 14.75 / DEFAULT_ROW_HEIGHT * rowHeightInPixels2);
    x2 = (int)Math.round((x2 / (Units.DEFAULT_CHARACTER_WIDTH * 256f) / 14.75) / DEFAULT_COL_WIDTH * colwidth2);

    Workbook newWb = newSheet.getWorkbook();
    CreationHelper newHelper = newWb.getCreationHelper();
    Drawing newDrawing = newSheet.getDrawingPatriarch();
    if ( newDrawing == null) {
      newDrawing = newSheet.createDrawingPatriarch();
    }
    ClientAnchor newAnchor = newHelper.createClientAnchor();
    newAnchor.setAnchorType(ClientAnchor.AnchorType.MOVE_AND_RESIZE);

    newAnchor.setRow1(row1);
    newAnchor.setCol1(col1);
    newAnchor.setDy1(y1 * Units.EMU_PER_POINT);
    newAnchor.setDx1((int)Math.round(x1 * Units.EMU_PER_PIXEL * Units.DEFAULT_CHARACTER_WIDTH / 256f));

    newAnchor.setCol2(col2);
    newAnchor.setRow2(row2); //second anchor determines bottom right position
    newAnchor.setDy2(y2 * Units.EMU_PER_POINT);
    newAnchor.setDx2((int)Math.round(x2 * Units.EMU_PER_PIXEL * Units.DEFAULT_CHARACTER_WIDTH / 256f));

    int newPictureIndex = newWb.addPicture(pictureData.getData(), pictureData.getPictureType());
    Picture picture = newDrawing.createPicture(newAnchor, newPictureIndex);
  }

  public static void main(String[] args) throws IOException {
    String outputFile = "newFile.xlsx";
    HSSFWorkbook oldWorkbook = createXLS();
    XSSFWorkbook newWorkbook = new XSSFWorkbook();

    HSSFSheet oldSheet = oldWorkbook.getSheetAt(0);
    String sheetName = oldSheet.getSheetName();
    XSSFSheet newSheet = newWorkbook.createSheet(sheetName);
    newSheet.setDefaultRowHeight(oldSheet.getDefaultRowHeight());
    newSheet.setDefaultColumnWidth(oldSheet.getDefaultColumnWidth());
    transferImages(oldSheet, newSheet);

    oldWorkbook.close();
    FileOutputStream fos = new FileOutputStream(outputFile);
    newWorkbook.write(fos);
    fos.close();
    newWorkbook.close();
  }
}

I read these answer:

apache poi XSSFClientAnchor not positioning picture with respect to dx1, dy1, dx2, dy2

How to set image size via HSSFWorkbook

Apache POI Excel sheet: resize a picture while keeping its ratio

What am I doing wrong?

sanchi82
  • 11
  • 2
  • "What am I doing wrong?": You are not thinking about what you suppose your helpers to do. We would need to: 1. create a `*.xls` file having at least one picture shape on a sheet drawing. 2. write the complete code which opens that `*.xls` file using `HSSF`, gets the `HSSFSheet` having the sheet drawing, gets the `Picture`, creates (or opens?) a `XSSFWorkbook`, creates (or gets?) the `XSSFSheet` and calls the `copyImage(Picture shape, HSSFSheet oldSheet, XSSFSheet newSheet)` then. 3. try to determine what the `transferImge (Sheet sheet, Sheet newSheet)` shall do and how it is involved here. – Axel Richter Apr 28 '22 at 07:08
  • Only then we would be able to reproduce your issue. I doubt, someone will do this. You have linked some of my answers. There you can see what "minimal complete example" means -> code to: copy - paste - compile - run. In your case you also should provide the source `*.xls` file somewhere to download. – Axel Richter Apr 28 '22 at 07:11
  • Hi! Thanks for you replay. I updated my code and now it is possibile to run it. It only needs a png image. It creates a xls file and a xlsx file. – sanchi82 May 02 '22 at 08:48
  • Sorry, I can't help. I guess I got what you are trying to achieve. But as told im my answers, you have linked, the drawing layers of `BIFF` (`*.xls`) and `Office Open XML` (`*.xlsx`) are too different and documented too less exact. So I am not able to provide a code which is able to copy the one into the other using `apache poi`. Maybe someone else will be able to. But I doubt that. – Axel Richter May 02 '22 at 15:35

0 Answers0