alibaba / easyexcel

快速、简洁、解决大文件内存溢出的java处理Excel工具
https://easyexcel.opensource.alibaba.com
Apache License 2.0
31.64k stars 7.46k forks source link

【功能困惑】关于不创建对象导出base64图片时设置单元格坐标的属性疑惑 #3625

Open LSL1618 opened 7 months ago

LSL1618 commented 7 months ago

建议先去看文档

快速开始常见问题

异常代码

// 单元格坐标属性源码
public class CoordinateData {
    private Integer firstRowIndex;
    private Integer firstColumnIndex;
    private Integer lastRowIndex;
    private Integer lastColumnIndex;

    private Integer relativeFirstRowIndex;
    private Integer relativeFirstColumnIndex;
    private Integer relativeLastRowIndex;
    private Integer relativeLastColumnIndex;
}

// 设置图片单元格坐标
if (CollectionUtils.isNotEmpty(form.getChartImages()) && firstSheet != null) {
    firstSheetBodyNumber += 1;
    firstSheetHeaderNumber += 2;
    List<ImageData> imageList = Lists.newArrayList();
    for (String chartImage : form.getChartImages()) {
        // 移除base64前缀
        String base64 = chartImage.replaceFirst("^data:.+?;base64,", "");
        ImageData imageData = new ImageData();
        imageData.setImageType(ImageData.ImageType.PICTURE_TYPE_PNG);
        imageData.setImage(Base64.decode(base64));
        // 图片外边距margin,上 右 下 左
        imageData.setTop(2);
        imageData.setRight(2);
        imageData.setBottom(2);
        imageData.setLeft(2);
        // 单元格坐标
        //imageData.setFirstRowIndex(0);
        //imageData.setFirstColumnIndex(firstSheetHeaderNumber);
        //imageData.setLastRowIndex(30 - 1);
        //imageData.setLastColumnIndex(firstSheetHeaderNumber + 20 - 1);
        imageData.setRelativeFirstRowIndex(-firstSheetBodyNumber);
        imageData.setRelativeFirstColumnIndex(firstSheetHeaderNumber);
        imageData.setRelativeLastRowIndex(-firstSheetBodyNumber + 30 - 1);
        imageData.setRelativeLastColumnIndex(firstSheetHeaderNumber + 20 - 1);
        firstSheetHeaderNumber += 20 + 2;
        imageList.add(imageData);
    }
    // 封装导出图片
    WriteCellData<Void> cellData = new WriteCellData<>();
    cellData.setType(CellDataTypeEnum.EMPTY);
    cellData.setImageDataList(imageList);
    List<WriteCellData> cellList = Lists.newArrayList(cellData);
    List<List<WriteCellData>> exportBody = Lists.newArrayList();
    exportBody.add(cellList);
    excelWriter.write(exportBody, firstSheet);
}
excelWriter.finish();

异常提示

大家尽量把问题一次性描述清楚,然后贴上全部异常,这样方便把问题一次性解决掉。 至少大家要符合一个原则就是,能让其他人复现出这个问题,如果无法复现,肯定无法解决。

问题描述

从属性名称上看,前4个坐标属性应该是指绝对坐标,后4个坐标属性应该是指相对坐标,然而实际导出效果却不是这样。我以为的绝对坐标实际上还是以相对坐标的位置插入的图片,这就与我预期的效果不符合了,搞得我只能以负数来设置左上角单元格和右下角单元格的相对坐标。假如有3行数据1行表头,有2列,有1张图片,预期图片插入起始位置为第1行第5列,结尾位置为第30行第25列, 则绝对坐标为[{row: 0, column: 5}, {row: 30, column: 5 + 20}],相对坐标为[{row: -4, column: 5}, {row: -4 + 30, column: 5 + 20}],目前只有相对坐标能达到效果,希望绝对坐标也能支持它应该有的效果。

ljluestc commented 1 month ago
import com.alibaba.excel.metadata.data.ImageData;
import com.alibaba.excel.metadata.data.WriteCellData;
import com.alibaba.excel.enums.CellDataTypeEnum;
import org.apache.commons.codec.binary.Base64;

import java.util.ArrayList;
import java.util.List;

public class ImageExport {

    public void exportImages(Form form, ExcelWriter excelWriter, Sheet firstSheet, int firstSheetHeaderNumber, int firstSheetBodyNumber) {
        if (CollectionUtils.isNotEmpty(form.getChartImages()) && firstSheet != null) {
            firstSheetBodyNumber += 1;
            firstSheetHeaderNumber += 2;
            List<ImageData> imageList = new ArrayList<>();
            for (String chartImage : form.getChartImages()) {
                // 移除base64前缀
                String base64 = chartImage.replaceFirst("^data:.+?;base64,", "");
                ImageData imageData = new ImageData();
                imageData.setImageType(ImageData.ImageType.PICTURE_TYPE_PNG);
                imageData.setImage(Base64.decodeBase64(base64));
                // 图片外边距 margin,上 右 下 左
                imageData.setTop(2);
                imageData.setRight(2);
                imageData.setBottom(2);
                imageData.setLeft(2);

                // 设置绝对坐标
                imageData.setFirstRowIndex(1); // 起始行应为1,因为Excel行从0开始计算
                imageData.setFirstColumnIndex(firstSheetHeaderNumber);
                imageData.setLastRowIndex(30); // 行索引为包含关系,所以结束行应为30
                imageData.setLastColumnIndex(firstSheetHeaderNumber + 20);

                // 注释掉相对坐标的代码
                // imageData.setRelativeFirstRowIndex(-firstSheetBodyNumber);
                // imageData.setRelativeFirstColumnIndex(firstSheetHeaderNumber);
                // imageData.setRelativeLastRowIndex(-firstSheetBodyNumber + 30 - 1);
                // imageData.setRelativeLastColumnIndex(firstSheetHeaderNumber + 20 - 1);

                firstSheetHeaderNumber += 22; // 20列图片宽度 + 2列间隔
                imageList.add(imageData);
            }
            // 封装导出图片
            WriteCellData<Void> cellData = new WriteCellData<>();
            cellData.setType(CellDataTypeEnum.EMPTY);
            cellData.setImageDataList(imageList);
            List<WriteCellData> cellList = new ArrayList<>();
            cellList.add(cellData);
            List<List<WriteCellData>> exportBody = new ArrayList<>();
            exportBody.add(cellList);
            excelWriter.write(exportBody, firstSheet);
        }
        excelWriter.finish();
    }

    public static void main(String[] args) {
        // 假设此处有初始化form, excelWriter, firstSheet等对象的代码
    }
}
LSL1618 commented 1 month ago

@ljluestc 我早就试过了没用的,要不然你以为我为什么会注释掉绝对坐标那一段代码,它的实际导出效果中图片起始位置会出现在表头行+数据行之和的下一行,这样的结果与预期不符;如果使用相对坐标那一段代码,那实际导出效果完全符合预期,图片起始位置会出现在第一行。