• Excel居中插入图片


    近期拿到一个需求,要求将图片写入Excel,且等比例缩小或者放大,且上下左右居中。

    因为历史原因,只能使用POI进行操作。遂去实践了一番。

    POI操作Excel插入图片(以XSSF为例),一般是如下操作

     1     public static void writeImageV1(XSSFSheet sheet,byte[] imageByte) {
     2         XSSFDrawing drawing = sheet.createDrawingPatriarch();
     3         XSSFClientAnchor anchors = new XSSFClientAnchor();
     4         anchors.setCol1(1);
     5         anchors.setCol2(13);
     6         anchors.setRow1(1);
     7         anchors.setRow2(13);
     8         anchors.setAnchorType(AnchorType.MOVE_AND_RESIZE);
     9         drawing.createPicture(anchors, sheet.getWorkbook().addPicture(imageByte, XSSFWorkbook.PICTURE_TYPE_JPEG));
    10     }

    但得到的效果如下

    图片自己被拉伸。这肯定不是客户想要的东西。所以,对于拉伸,有两种选择

    1、自己根据锚点去调整图片的长度宽度

    2、调用XSSFPicture.resize() 或者 XSSFPicture.resize(double scale);

    先说第二种方式

     1     public static void writeImageV2(XSSFSheet sheet,byte[] imageByte) {
     2         XSSFDrawing drawing = sheet.createDrawingPatriarch();
     3         XSSFClientAnchor anchors = new XSSFClientAnchor();
     4         anchors.setCol1(1);
     5         anchors.setCol2(13);
     6         anchors.setRow1(1);
     7         anchors.setRow2(13);
     8         anchors.setAnchorType(AnchorType.MOVE_AND_RESIZE);
     9         XSSFPicture pic = drawing.createPicture(anchors, sheet.getWorkbook().addPicture(imageByte, XSSFWorkbook.PICTURE_TYPE_JPEG));
    10         pic.resize();
    11     }

    这个就刺激了,有兴趣可以自己去试试。

    这时回到第一种方式。直接进行相对位置的调整。直接进行相对位置的调整。先尝试缩小100个单位。

     1     public static void writeImageV3(XSSFSheet sheet,byte[] imageByte) {
     2         XSSFDrawing drawing = sheet.createDrawingPatriarch();
     3         XSSFClientAnchor anchors = new XSSFClientAnchor();
     4         anchors.setCol1(1);
     5         anchors.setCol2(13);
     6         anchors.setRow1(1);
     7         anchors.setRow2(13);
     8         
     9         anchors.setDx1(Units.EMU_PER_PIXEL * 100);
    10         anchors.setDx2(Units.EMU_PER_PIXEL *(-100));
    11         anchors.setDy1(Units.EMU_PER_PIXEL *(100));
    12         anchors.setDy2(Units.EMU_PER_PIXEL *(-100));
    13         anchors.setAnchorType(AnchorType.MOVE_AND_RESIZE);
    14         drawing.createPicture(anchors, sheet.getWorkbook().addPicture(imageByte, XSSFWorkbook.PICTURE_TYPE_JPEG));
    15     }

    效果如下

    但是看上去并不是这么回事。左上角貌似恰好只移动了一个单元格。看API说明。

    Within the first cell ??换句话说,只能在cell单元格里面进行调整??这tm不是捣乱吗?

    等等,不对,原始图片左下角单元格不是(13,B) 吗?为何调整后的图片左下角却是(9,C)?如果是限制在单元格里面,为何此处可以跳出单元格???(有知道的朋友不妨留个言)

    仅从目前得到的信息来看:调整图片似乎只能往左上的方向进行调整,而不能往右下进行调整。

    那只能调整思路,切换锚点了。

     1     public static void writeImageV4(XSSFSheet sheet,byte[] imageByte) {
     2         XSSFDrawing drawing = sheet.createDrawingPatriarch();
     3         XSSFClientAnchor anchors = new XSSFClientAnchor();
     4         int col1 = 1,col2 = 13,row1 = 1,row2 = 13; //四个坐标
     5         anchors.setCol1(col2); anchors.setCol2(col2); //锚点1
     6         anchors.setRow1(row2); anchors.setRow2(row2); //锚点2
     7         //计算区域的大小
     8         XSSFRow row = sheet.createRow(row1);
     9         double rowHeight = row.getHeightInPoints()/72*96; //行高,此处的值不精确
    10         double colWidth  = sheet.getColumnWidthInPixels(col1); //列宽(注意,可能不准)
    11         logger.info("rowHeight {} colWidth {}",rowHeight,colWidth);
    12         double collWidthSum = colWidth * (col2 - col1), rowHeightSum = rowHeight * (row2 - row1);  //区域的实际大小
    13         logger.info("collWidthSum {} rowHeightSum {}",collWidthSum,rowHeightSum);
    14         InputStream bais = new ByteArrayInputStream(imageByte);  //图片大小
    15         int imgaeWidth = 0,imageHeight = 0; //图片宽高
    16         try {
    17             BufferedImage bufferImage = ImageIO.read(bais);
    18             imgaeWidth = bufferImage.getWidth(); 
    19             imageHeight = bufferImage.getHeight();
    20         } catch (IOException e) { /** TODO 异常处理**/}
    21         finally { /** TODO 关闭流 **/ }
    22         logger.info("imgaeWidth {} imageHeight {}",imgaeWidth,imageHeight);
    23         double scale = Math.min(collWidthSum/imgaeWidth, rowHeightSum/imageHeight);  //计算缩放比例
    24         logger.info("scale {}",scale);
    25         double realImageWidth = imgaeWidth*scale,realImageHeight = imageHeight*scale;  //处理后图片的大小
    26         logger.info("realImageWidth {} realImageHeight {}",realImageWidth,realImageHeight);
    27         double moveX = realImageWidth == collWidthSum ? 0 : (collWidthSum - realImageWidth)/2; //计算出需要图片需要移动的坐标 X轴
    28         double moveY = realImageHeight == rowHeightSum ? 0 : (rowHeightSum - realImageHeight)/2; //计算出需要图片需要移动的坐标 Y轴
    29         logger.info("moveX {} moveY {}",moveX,moveY);
    30         anchors.setDx1(Units.EMU_PER_PIXEL *(int)(-realImageWidth - moveX));
    31         anchors.setDx2(Units.EMU_PER_PIXEL *(int)(-moveX));
    32         anchors.setDy1(Units.EMU_PER_PIXEL *(int)(-realImageHeight - moveY));
    33         anchors.setDy2(Units.EMU_PER_PIXEL *(int)(-moveY));
    34         anchors.setAnchorType(AnchorType.MOVE_AND_RESIZE);
    35         drawing.createPicture(anchors, sheet.getWorkbook().addPicture(imageByte, XSSFWorkbook.PICTURE_TYPE_JPEG));
    36     }

    效果如下

    因为计算行高和列宽都不是精确值,所以,上下左右居中,会稍微有一点点偏移~

    有兴趣的朋友可以自己尝试写一个更精确的。

     java文件如下

    https://files.cnblogs.com/files/brave-rocker/WriteImageToExcel.java.zip

  • 相关阅读:
    C# 字典类 Dictionary 基本用法 Mark
    SQL语句监测耗时
    jQuery Select Option 操作 删除新增
    C# DataTable 过滤重复数据
    IE8 overflow:hidden 无效问题解决方案
    动态拼接LINQ 查询条件
    解决.net中"未能创建 Mutex”异常
    创建Cookies 包含子健和无子健的创建及用法 做个笔记留着参考
    常用的一些加密算法,留着以备不时之需
    Centos7 nginx安装
  • 原文地址:https://www.cnblogs.com/brave-rocker/p/14674267.html
Copyright © 2020-2023  润新知