poi 移除图片_Excel中读取图片的坑-poi-2007

当使用POI解析包含图片的Excel时,遇到NullPointerException。问题源于某些图片被解析为CMYKJPEGImageReader,导致getImageMetadata()返回null。解决办法是移除Excel中的图片,避免此类异常。
部署运行你感兴趣的模型镜像

现象:

在web页面导入excel文件,excel中包含图片,在后台进行解析的时候,有时候会报NullPointerException。

问题排查:

由于POI里面并没有把这里的错误信息输出到日志文件,在服务器上报错后,从后台日志文件中根本看不出什么。

在本地调试的时候,又没有报错,搞得我们一直以为是临时文件的没有正常读取导致的,而且我们把tomcat的temp目录删除后重启,竟然神奇又不报错了。

哪知道昨天客户现场又报这个错,但是我刚刚删除了temp目录,重启了tomcat啊!!!受不了,我死活都要找到原因,说干就干,把线上的temp目录覆盖我本地的temp目录,

本地环境启起来,拿那个现场出错的excel一试,错误没有辜负我的期望,如期而遇,控制台错误日志如下(吐槽POI,这个错误日志竟然只输出控制台):

java.lang.NullPointerException

at org.apache.poi.ss.util.ImageUtils.getResolution(ImageUtils.java:117)

at org.apache.poi.ss.util.ImageUtils.getImageDimension(ImageUtils.java:79)

at org.apache.poi.ss.util.ImageUtils.setPreferredSize(ImageUtils.java:141)

at org.apache.poi.xssf.usermodel.XSSFPicture.getPreferredSize(XSSFPicture.java:221)

at org.apache.poi.xssf.usermodel.XSSFPicture.getPreferredSize(XSSFPicture.java:210)

at org.apache.poi.xssf.usermodel.XSSFPicture.getPreferredSize(XSSFPicture.java:200)

at com.hentre.all580.core.util.excel.ExcelUtilXlsx.getPicValue(ExcelUtilXlsx.java:51)

at com.hentre.all580.core.util.excel.ExcelUtil.getCellValue(ExcelUtil.java:118)

at com.hentre.all580.core.util.excel.ExcelHandler.getValue(ExcelHandler.java:155)

at com.hentre.all580.core.util.excel.JourneyExcelHandler.templateResolve(JourneyExcelHandler.java:64)

at com.hentre.all580.core.util.excel.JourneyExcelHandler.templateResolve(JourneyExcelHandler.java:115)

at com.hentre.all580.coreplatform.controller.upload.ImportItineraryHandler.doExecute(ImportItineraryHandler.java:41)

at com.hentre.all580.coreplatform.controller.upload.AbstractImportHandler.execute(AbstractImportHandler.java:41)

at com.hentre.all580.coreplatform.controller.upload.BaseUploadController.upload(BaseUploadController.java:184)

...

找到报错地方的代码如下:

public static int[] getResolution(ImageReader r) throws IOException {

int hdpi = 96;

int vdpi = 96;

double mm2inch = 25.4D;

Element node = (Element)r.getImageMetadata(0).getAsTree("javax_imageio_1.0"); //这一行抛错

NodeList lst = node.getElementsByTagName("HorizontalPixelSize");

if(lst != null && lst.getLength() == 1) {

hdpi = (int)(mm2inch / (double)Float.parseFloat(((Element)lst.item(0)).getAttribute("value")));

}

lst = node.getElementsByTagName("VerticalPixelSize");

if(lst != null && lst.getLength() == 1) {

vdpi = (int)(mm2inch / (double)Float.parseFloat(((Element)lst.item(0)).getAttribute("value")));

}

return new int[]{hdpi, vdpi};

}

从上面的现象看,一直以为是临时文件的读取问题,反复调试临时文件的创建和读取,此处略过10000字,poi里面解析图片的代码复杂。。。。。

偶然在调试在上面抛错那里的代码时,发现r的类型竟然是不一样的,正常的情况下是JPEGImageReader,报错的情况竟然是CMYKJPEGImageReader。

找到CMYKJPEGImageReader的getImageMetadata()方法,代码如下:

public IIOMetadata getImageMetadata(int imageIndex) throws IOException {

return null;

}

瞬间明白了,但是这坑爹的poi怎么会把图片解析成这个类型呢?为什么同一图片,有时候是,有时候又不是呢?百度了一下,大概说明如下:

CMYK也称作印刷色彩模式,顾名思义就是用来印刷的。

它和RGB相比有一个很大的不同:RGB模式是一种发光的色彩模式,你在一间黑暗的房间内仍然可以看见屏幕上的内容;

CMYK是一种依靠反光的色彩模式,我们是怎样阅读报纸的内容呢?是由阳光或灯光照射到报纸上,再反射到我们的眼中,才看到内容。它需要有外界光源,如果你在黑暗房间内是无法阅读报纸的。

只要在屏幕上显示的图像,就是RGB模式表现的。只要是在印刷品上看到的图像,就是CMYK模式表现的。比如期刊、杂志、报纸、宣传画等,都是印刷出来的,那么就是CMYK模式的了。

总结:

发现如果用POI从excel中获取图片的话,那么上面的问题是无解的。咱惹不起,只能躲了,果断在导入模板里面把图片删除了,然后把这个原则深深的记在了脑海里!

我真的是太机智了。。。

您可能感兴趣的与本文相关的镜像

Stable-Diffusion-3.5

Stable-Diffusion-3.5

图片生成
Stable-Diffusion

Stable Diffusion 3.5 (SD 3.5) 是由 Stability AI 推出的新一代文本到图像生成模型,相比 3.0 版本,它提升了图像质量、运行速度和硬件效率

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值