最近把图片系统迁移到x-file-storage,发现x-file-storage使用thumbnail还是没有处理图片质量问题和PNG透明背景变黑的问题。
看了下以前的代码,又研究了下x-file-storage源码,写了个辅助类解决了这个问题
package org.dromara.x.file.storage.core.upload;
import net.coobird.thumbnailator.ThumbnailParameter;
import net.coobird.thumbnailator.Thumbnails;
import net.coobird.thumbnailator.filters.ImageFilter;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.InputStream;
import java.util.function.Consumer;
/**
* x-file-storage支持缩略图透明色处理为白色背景
* 缩略图自动质量:长x宽=40000以下使用高质量,否则使用普通质量
* @author JIM 2024-03-07
*/
public class CcUploadPretreatment extends UploadPretreatment {
private static final double JPEG_QUALITY_HIGH = 0.95f;
private static final double JPEG_QUALITY_LOW = 0.85f; //Thumbnailator 默认的质量
private static class ThumbnailsImgFilter implements ImageFilter { //将压缩后的图片背景设置为白色
@Override
public BufferedImage apply(BufferedImage img) {
int w = img.getWidth();
int h = img.getHeight();
BufferedImage newImage = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
Graphics2D graphic = newImage.createGraphics();
graphic.setColor(Color.white);//white
graphic.fillRect(0, 0, w, h);
graphic.drawRenderedImage(img, null);
graphic.dispose();
return newImage;
}
}
private static final ThumbnailsImgFilter thumbnailsImgFilter = new ThumbnailsImgFilter();
public CcUploadPretreatment(UploadPretreatment pre) {
setFileStorageService(pre.getFileStorageService());
setPlatform(pre.getPlatform());
setFileWrapper(pre.getFileWrapper());
setThumbnailBytes(pre.getThumbnailBytes());
setThumbnailSuffix(pre.getThumbnailSuffix());
setObjectId(pre.getObjectId());
setObjectType(pre.getObjectType());
setPath(pre.getPath());
setSaveFilename(pre.getSaveFilename());
setSaveThFilename(pre.getSaveThFilename());
setThContentType(pre.getThContentType());
setMetadata(pre.getMetadata());
setUserMetadata(pre.getUserMetadata());
setThMetadata(pre.getThMetadata());
setThUserMetadata(pre.getThUserMetadata());
setNotSupportMetadataThrowException(pre.getNotSupportMetadataThrowException());
setNotSupportAclThrowException(pre.getNotSupportAclThrowException());
setAttr(pre.getAttr());
setProgressListener(pre.getProgressListener());
setInputStreamPlus(pre.getInputStreamPlusDirect());
setFileAcl(pre.getFileAcl());
setThFileAcl(pre.getThFileAcl());
setHashCalculatorManager(pre.getHashCalculatorManager());
}
private void configureThumbnail(Thumbnails.Builder<? extends InputStream> th, int width, int height) {
th.size(width, height);
th.outputQuality(width * height > 40000 ? JPEG_QUALITY_LOW : JPEG_QUALITY_HIGH);
th.addFilter(thumbnailsImgFilter);
}
@Override
public UploadPretreatment thumbnail(int width, int height) {
return thumbnail(th -> configureThumbnail(th, width, height));
}
}
使用方法:
在upload前,使用本类包装一下再调用upload方法。
原代码:
@PostMapping("upload")
@ApiOperation(value = "将文件上传至临时文件区", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public FileInfo upload(@RequestParam("file") MultipartFile file, Integer thumbWidth, Integer thumbHeight) {
UploadPretreatment uploadPretreatment = fileStorageService.of(file).setPath(GlobalEx.UPLOAD_TEMP_DIR + "/");
if(thumbWidth != null && thumbHeight != null){
uploadPretreatment.thumbnail(thumbWidth, thumbHeight);
}
return uploadPretreatment.upload();
}
修改为:
@PostMapping("upload")
@ApiOperation(value = "将文件上传至临时文件区", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public FileInfo upload(@RequestParam("file") MultipartFile file, Integer thumbWidth, Integer thumbHeight) {
UploadPretreatment uploadPretreatment = fileStorageService.of(file).setPath(GlobalEx.UPLOAD_TEMP_DIR + "/");
CcUploadPretreatment ccUploadPretreatment = new CcUploadPretreatment(uploadPretreatment);
if(thumbWidth != null && thumbHeight != null){
ccUploadPretreatment.thumbnail(thumbWidth, thumbHeight);
}
return ccUploadPretreatment.upload();
}
图片质量0.95已经差不多了,当然你也可以使用1.0(100%)和0.95差别感觉不大但是缩略图大了1/3左右