SpringBoot中使用imageJ报错java.awt.HeadlessException的解决方法

ImageJ是一款基于Java的开源图像处理软件,目前在生物及医学图像分析中使用比较广泛。注意,这个使用广泛是Java客户端软件使用比较广泛,而很少作为类库应用于Java工程。

由于项目中需要编写爬虫进行模拟登录,登录时需要处理图片验证码,而自己写的图片处理方式并不能达到想要的结果,例如去噪,去除杂点,二值化等操作,所以就使用了这款Java的开源图像处理软件。

目前此软件有两个版本,imagej1.x和imagej2,项目中使用了imagej 1.52p版本,其实是想使用imagej2版本的,但是因为在项目中使用了阿里云的maven仓库,而阿里云实际只代理了maven center及 jcenter的maven仓库,imagej1.x在maven中央仓库中,imagej2版本在https://mvnrepository.com/中能够搜的到,但是imagej2并未发布到中央仓库,因此,阿里云的maven仓库中也没有这个版本。

言归正传,现在看一下imagej的使用方式:

1、在pom.xml里面配置

            <dependency>
                <groupId>net.imagej</groupId>
                <artifactId>ij</artifactId>
                <version>1.52p</version>
            </dependency>

2、 在Java代码中使用

            // 初始图片路径
            IJ.open(openPath);
            // 设置大小
            IJ.run("Size...", "width=120 height=40 constrain interpolate");
            // 去噪
            IJ.run("Remove Outliers...", "radius=1 threshold=50 which=Dark");
            // 去除杂点
            IJ.run("Despeckle");
            // 二值
            IJ.run("Make Binary");
            // 另存图片
            IJ.save(savePath);

如上所示,此类库使用比较简单方便,其在Java项目中以及SpringMvc中使用没有任何问题,但是由于新项目使用了SpringBoot,其在运行的时候总是抛出java.awt.HeadlessException异常。如是问题的解决开始了,首先了解一下:

1. 什么是 java.awt.headless?

Headless模式是系统的一种配置模式。在系统可能缺少显示设备、键盘或鼠标这些外设的情况下可以使用该模式。

2. 何时使用和headless mode?

Headless模式虽然不是我们愿意见到的,但事实上我们却常常需要在该模式下工作,尤其是服务器端程序开发者。因为服务器(如提供Web服务的主机)往往可能缺少前述设备,但又需要使用他们提供的功能,生成相应的数据,以提供给客户端(如浏览器所在的配有相关的显示设备、键盘和鼠标的主机)。

3. 如何使用和Headless mode?

一般是在程序开始激活headless模式,告诉程序,现在你要工作在Headless mode下,就不要指望硬件帮忙了,你得自力更生,依靠系统的计算能力模拟出这些特性来:

            System.setProperty("java.awt.headless", "true");

现在知道了什么是headless,然后又在网上找到了在SpringBoot中如何解决HeadlessException的方法,那就是在SpringApplication启动类中修改为如下代码:

    SpringApplicationBuilder builder = new SpringApplicationBuilder(YourApplication.class);
    builder.headless(false).run(args);

可以看出,SpringBoot应该是默认开启了headless模式,所以要在项目启动加载时关闭。项目重新启动,运行一切正常,没有报错,现在开开心心,高高兴兴的打包,发布测试,然而项目原先的登录验证码不显示了。本地开发环境是Windows,发布环境是Linux,那么问题就是在这了,Windows下面关闭了headless模式,Java可以调用系统的相关类库实现图片的显示,因为Windows是有显示设备的,而Linux没有显示设备,此时,Java调用先关类库时就会抛出异常,那么说明我么不能只靠关闭headless来解决这个问题。

因此只能查询相关资料,查看imagej如何在headless模式下正常使用,从imagej官网中(Running Headless)我们可以看到imagej提供了headless的多种解决方法,但是这几种方式并不是我们能够使用的,于是参考官方在github上的源码(https://github.com/imagej/imagej/blob/master/src/test/java/net/imagej/app/MainTest.java)找到了如下源码:

            final ImageJ ij = new ImageJ();
            ij.launch("--headless");

简直是兴奋溢于言表啊,就这么简单的问题解决了,赶紧copy到自己项目中,然而报错,提示没有这个方法,又一场乐极生悲,那么再仔细看,仔细找,过程不多描述,最后发现,这个是imagej2开启headless的方式,而imagej1.x需要通过补丁的方式来解决,都怪没有仔细看官网介绍,其实在官网中有一点点描述,但是并没有明确方法,那么再从imagej1.x的源码下手(GitHub - imagej/ij1-patcher: Extension points for ImageJ via runtime patching to support (limited) headless operation and ImageJ2's legacy layer),里面详细介绍了如何启用headless模式:

            <dependency>
            	<groupId>net.imagej</groupId>
            	<artifactId>ij1-patcher</artifactId>
            	<version>1.0.0</version>
            </dependency>
            // The first parameter is a class loader, asking for a new,
            // special-purpose class loader to be created; the second parameter
            // asks for headless mode.
            LegacyEnvironment ij1 = new LegacyEnvironment(null, true);
            ij1.runMacro("open('" + path + "');");
            [... process the image ...]
            ij1.runMacro("saveAs('jpeg', '" + outputPath + "');");

好了,现在再将此代码copy的项目中,现在项目中代码如下:

            LegacyEnvironment ij1 = new LegacyEnvironment(null, true);
            ij1.runMacro("open('" + openPath + "');", "");
            ij1.run("Size...", "width=120 height=40 constrain interpolate");
            ij1.run("Remove Outliers...", "radius=1 threshold=50 which=Dark");
            ij1.run("Despeckle", "");
            ij1.run("Make Binary", "");
            ij1.runMacro("saveAs('jpeg', '" + savePath + "');", "");

请注意LegacyEnvironment的第二个参数true就是是否开启headless模式,一定要执行open和save等菜单操作的时候使用runMacro方法,去燥,二值等操作时使用run方法。此处应该是imagej在执行open和save等menu操作时,会用到headless相关方法,而其他图片处理时不会用到。

遗留问题:因为imagej1.x使用的是运行时修补的方式来解决这个headless问题,在代码中会getContextClassLoader,因此当图片处理抛出异常时,会导致整个SpringBoot工程关闭,所以有条件请尽量升级imagej2版本,直接launch来解决这个问题。

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

全栈程序猿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值