1.需求
业务要求对png, jpg, jpeg, webp 格式图片进行等比例压缩
2.开发中遇到的问题
使用 Thumbnails 包, 发现只能压缩 jpg 和 jpeg , 不能压缩webp
接着找到了 webp-imageio 解决webp , 又发现 这俩都不支持 png ,
接着找到了 OpenViewerFX 去处理png…
扑你X母…
3. 实现代码
3.1 pom 引用
<!--压缩png-->
<dependency>
<groupId>org.jpedal</groupId>
<artifactId>OpenViewerFX</artifactId>
<version>6.6.14</version>
</dependency>
<!-- Thumbnailator: 图片缩放和压缩工具 -->
<dependency>
<groupId>net.coobird</groupId>
<artifactId>thumbnailator</artifactId>
<version>0.4.14</version>
</dependency>
<!-- TwelveMonkeys: 支持更多图片格式 -->
<dependency>
<groupId>com.twelvemonkeys.imageio</groupId>
<artifactId>imageio-core</artifactId>
<version>3.9.4</version>
</dependency>
<dependency>
<groupId>com.twelvemonkeys.imageio</groupId>
<artifactId>imageio-jpeg</artifactId>
<version>3.9.4</version>
</dependency>
<dependency>
<groupId>com.twelvemonkeys.imageio</groupId>
<artifactId>imageio-webp</artifactId>
<version>3.9.4</version>
</dependency>
<!--压缩webp-->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-imaging</artifactId>
<version>1.0-alpha1</version>
</dependency>
<dependency>
<groupId>org.sejda.imageio</groupId>
<artifactId>webp-imageio</artifactId>
<version>0.1.6</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.imgscalr/imgscalr-lib -->
<dependency>
<groupId>org.imgscalr</groupId>
<artifactId>imgscalr-lib</artifactId>
<version>4.2</version>
</dependency>
3.2 controller 代码
我这里自己定死了生产图片文件夹的路径 , 各位大神按照自己实际的需求改动
package com.example.controller;
import com.example.service.ImageCompressionService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import javax.imageio.ImageIO;
import javax.imageio.ImageReader;
import java.io.File;
import java.io.IOException;
import java.util.Iterator;
/**
* @ClassName: ImageCompressionController
* @Description: TODO
* @Author: 赵狗
* @Date: 2024/8/23 15:04
*/
@RequestMapping("/imageApi")
@RestController
public class ImageCompressionController {
@Autowired
private ImageCompressionService imageCompressionService;
/**
* 图片压缩方法
* @param file
* @param quality
* @return
* @throws IOException
*/
@PostMapping("/compressBySize")
public String compressImageBySize(@RequestParam("file") MultipartFile file,
@RequestParam("quality") String quality
) throws IOException {
String outputPath = "F:\\images\\" + "compressed_size_" + file.getOriginalFilename();
File outputFile = new File(outputPath);
prepareOutputDirectory(outputFile);
File inputFile = convertMultipartFileToFile(file);
// 将quality转为 float
float qualityFloat = Float.parseFloat(quality);
imageCompressionService.compressImageBySize(inputFile, outputFile,qualityFloat);
inputFile.delete();
return "File compressed successfully by size: " + outputFile.getAbsolutePath();
}
/**
* 判断文件夹是否存在, 如果没有则创建
* @param outputFile
*/
private void prepareOutputDirectory(File outputFile) {
if (!outputFile.getParentFile().exists()) {
outputFile.getParentFile().mkdirs();
}
}
/**
* 将MultipartFile转换为File
* @param file
* @return
* @throws IOException
*/
private File convertMultipartFileToFile(MultipartFile file) throws IOException {
File convFile = new File(System.getProperty("java.io.tmpdir") + "/" + file.getOriginalFilename());
file.transferTo(convFile);
return convFile;
}
public boolean isWebPSupported() {
Iterator<ImageReader> readers = ImageIO.getImageReadersByFormatName("webp");
return readers.hasNext();
}
}
3.3 Service 代码
package com.example.service;
import com.idrsolutions.image.png.PngCompressor;
import com.luciad.imageio.webp.WebPWriteParam;
import net.coobird.thumbnailator.Thumbnails;
import org.springframework.stereotype.Service;
import javax.imageio.IIOImage;
import javax.imageio.ImageIO;
import javax.imageio.ImageWriteParam;
import javax.imageio.ImageWriter;
import javax.imageio.stream.ImageOutputStream;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.Iterator;
/**
* @ClassName: ImageCompressionService
* @Description: TODO
* @Author: 赵狗
* @Date: 2024/8/23 15:03
*/
@Service
public class ImageCompressionService {
private static final int DEFAULT_QUALITY = 80; // 默认压缩质量为 80
/**
* 压缩图片方法
* @param inputFile
* @param outputFile
* @param quality
* @throws IOException
*/
public void compressImageBySize(File inputFile, File outputFile, float quality) throws IOException {
// 根据输入文件的后缀名获取文件格式
String formatName = getFileExtension(inputFile);
// 根据不同的文件格式,调用相应的压缩方法
if ("webp".equalsIgnoreCase(formatName)) {
// 对webp格式的图片进行压缩
compressWebpImage(inputFile,outputFile,quality);
} else if("png".equalsIgnoreCase(formatName)){
// 对png格式的图片进行压缩
compressPngImage(inputFile, outputFile);
} else {
// 对jpg或其他格式的图片进行压缩,这里假设jpg的压缩方法与其他格式不同
compressJpgImage(inputFile, outputFile, quality, formatName);
}
}
/**
* 压缩jpg 以及 jpeg 格式的图片方法
* @param inputFile
* @param outputFile
* @param quality
* @param formatName
* @throws IOException
*/
private void compressJpgImage(File inputFile, File outputFile, float quality, String formatName) throws IOException {
// 压缩jpg 以及 jpeg 格式的图片
Thumbnails.of(inputFile)
.scale(1) // 明确告诉库不需要改变图片尺寸
.outputQuality(quality) // 设置输出图片的质量
.outputFormat(formatName) // 保持原有格式
.toFile(outputFile);
}
/**
* 压缩png格式图片方法
* @param inputFile
* @param outputFile
* @throws IOException
*/
private void compressPngImage(File inputFile, File outputFile) throws IOException {
PngCompressor.compress(inputFile, outputFile);
}
/**
* 压缩webp格式图片方法
* @param inputFile
* @param outputFile
* @param quality
* @throws IOException
*/
public void compressWebpImage(File inputFile, File outputFile, float quality) throws IOException {
// 读取输入的WebP图像
BufferedImage image = ImageIO.read(inputFile);
// 获取WebP格式的ImageWriter
Iterator<ImageWriter> writers = ImageIO.getImageWritersByFormatName("webp");
if (!writers.hasNext()) {
throw new IllegalStateException("No WebP writer found");
}
ImageWriter writer = writers.next();
// 设置输出流
try (ImageOutputStream ios = ImageIO.createImageOutputStream(outputFile)) {
writer.setOutput(ios);
// 设置压缩参数
WebPWriteParam writeParam = (WebPWriteParam) writer.getDefaultWriteParam();
writeParam.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
writeParam.setCompressionType("Lossy");
writeParam.setCompressionQuality(quality); // 设置压缩质量,值范围 0.0 ~ 1.0
// 写出压缩后的WebP图像
writer.write(null, new IIOImage(image, null, null), writeParam);
} finally {
writer.dispose();
}
}
/**
* 获取图片类型方法
* @param file
* @return
*/
private String getFileExtension(File file) {
String name = file.getName();
return name.substring(name.lastIndexOf('.') + 1).toLowerCase();
}
}
3.4 apifox 调用
3.5 效果图
3.5.1 压缩前:
3.5.2 压缩后