项目:文件存储系统
需求: 需要开发一个图片压缩接口,需要对图片进行按比例压缩
方案:选择用thumbnailator来实现图片压缩,
- thumbnailator git地址:https://github.com/coobird/thumbnailator/wiki/Examples
第一版代码:
/**
* 压缩图片方法
* @param in
* @throws Exception
*/
public static BufferedImage compressionImage(InputStream in ,float quality)throws Exception{
//默认图片质量因子
if (quality == 0) {
quality = 0.6f;
}
BufferedImage bufferedImage = ImageIO.read(in);
double scale=1/computeSize(bufferedImage);
Thumbnails.of(bufferedImage);
BufferedImage thumbnail= Thumbnails.of(bufferedImage)
.outputFormat(Constant.IMAGE_FORMAT_JPEG)
.scale(scale)
.outputQuality(quality)
.asBufferedImage();
in.close();
return thumbnail;
}
使用:
BufferedImage bufferedImage= ImageUtil.compressionImage(inputStream, fileDownloadVo.getQuality());
String imageSize= ImageUtil.getImageMeasure(bufferedImage);
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ImageIO.write(bufferedImage, Constant.IMAGE_FORMAT_JPEG,byteArrayOutputStream);
byte[] bytes = byteArrayOutputStream.toByteArray();
long fileSize = bytes.length;
问题:
测试出现了图片背景颜色会发生变化,不符合要求,
问题原因:
- Java上传图片时,对某些图片进行缩放、裁剪或者生成缩略图时会蒙上一层红色,经过检查只要经过ImageIO.read()方法读取后再保存,该图片便已经变成红图。因此,可以推测直接原因在于ImageIO.read()方法加载图片的过程存在问题
- 经过查阅得知ImageIO.read()方法读取图片时可能存在不正确处理图片ICC信息的问题,ICC为JPEG图片格式中的一种头部信息(进行校验图片颜色的信息),导致渲染图片前景色时蒙上一层红色。
- 发现报红的图片比不报红的图片头文件缺少一段信息
解决方案:
使用阿里巴巴simpleimage
SimpleImage github地址:https://github.com/alibaba/simpleimage
依赖jar:commons-io-2.4.jar
commons-lang.jar
commons-logging-1.1.1.jar
jai_codec-1.1.3.jar(这个jar包可以在git源码里下载,需要手动添加到项目)
jai_core-1.1.3.jar(这个jar包可以在git源码里下载,需要手动添加到项目)
第二版代码:
/**
* 压缩图片方法
* @param in
* @throws Exception
*/
public static BufferedImage compressionImage(InputStream in ,float quality)throws Exception{
//默认图片质量因子
if (quality == 0) {
quality = 0.6f;
}
ImageWrapper imageWrapper = ImageReadHelper.read(in);
BufferedImage bufferedImage = imageWrapper.getAsBufferedImage();
double scale=1/computeSize(bufferedImage);
Thumbnails.of(bufferedImage);
BufferedImage thumbnail= Thumbnails.of(bufferedImage)
.outputFormat(Constant.IMAGE_FORMAT_JPEG)
.scale(scale)
.outputQuality(quality)
.asBufferedImage();
in.close();
return thumbnail;
}
使用
BufferedImage bufferedImage= ImageUtil.compressionImage(inputStream, fileDownloadVo);
String imageSize= ImageUtil.getImageMeasure(bufferedImage);
ImageWrapper imageWrapper = new ImageWrapper(bufferedImage);
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ImageWriteHelper.write(imageWrapper, byteArrayOutputStream, ImageFormat.JPEG, new WriteParameter());
byte[] bytes = byteArrayOutputStream.toByteArray();
long fileSize = bytes.length;
第二版测试:
图片变色问题修复,出现新的问题,图片压缩后图片变大了,557KB的图片变成了900多KB,这就尴尬了
问题排查:
通过排查,问题出现在ImageWriteHelper.write(imageWrapper, byteArrayOutputStream, ImageFormat.JPEG, new WriteParameter());这边具体什么原因我不知道,如果有知道的大佬麻烦告知下,
解决方案
默认的采样率是93,设置成60后,557KB的图片变成了440KB,符合要求
第三版代码:
BufferedImage bufferedImage= ImageUtil.compressionImage(inputStream, fileDownloadVo);
String imageSize= ImageUtil.getImageMeasure(bufferedImage);
//设置采样参60.默认93,太大的图片大小会变大不符合压缩要求
ImageWrapper imageWrapper = new ImageWrapper(bufferedImage,60);
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ImageWriteHelper.write(imageWrapper, byteArrayOutputStream, ImageFormat.JPEG, new WriteParameter());
byte[] bytes = byteArrayOutputStream.toByteArray();
long fileSize = bytes.length;
总结:
网络上对于图片压缩过程中会出现的问题记录和解决方案比较少,这边记录下也分享出来,希望你们有帮助,如果有问题的地方麻烦各位大佬指正.