首先导入thumbnailator包,关于这个的使用可以看别的博文。
pom文件引入:
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
<version>3.10.2</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.4</version>
</dependency>
<dependency>
<groupId>net.coobird</groupId>
<artifactId>thumbnailator</artifactId>
<version>0.4.8</version>
</dependency>
然后写一个压缩的工具类:
import lombok.extern.slf4j.Slf4j;
import net.coobird.thumbnailator.Thumbnails;
import org.apache.commons.io.IOUtils;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
/**
* 压缩工具类
*/
@Slf4j
public class CompressionUtil {
/**
* 压缩后的图片大小
*/
private static final long AFTER_COMPRESSION_FILE_SIZE = 500L;
/**方便通过文件流来给到thumbnailator的操作字节流
* 传入stream然后转化为byte[]然后得到压缩后的数组
*/
public static byte[] streamToBytesAndCompression(InputStream inputStream, Integer userId) throws IOException {
//使用的是org.apache.commons.io.IOUtils
byte[] bytes = IOUtils.toByteArray(inputStream);
//图片小于500kb
bytes = compressPicForScale(bytes, AFTER_COMPRESSION_FILE_SIZE, userId.toString());
return bytes;
}
/**
* 根据指定大小压缩图片
*
* @param imageBytes 源图片字节数组
* @param desFileSize 指定图片大小,单位kb
* @param imageId 影像编号
* @return 压缩质量后的图片字节数组
*/
public static byte[] compressPicForScale(byte[] imageBytes, long desFileSize, String imageId) {
if (imageBytes == null || imageBytes.length <= 0 || imageBytes.length < desFileSize * 1024) {
return imageBytes;
}
long srcSize = imageBytes.length;
double accuracy = getAccuracy(srcSize / 1024);
try {
while (imageBytes.length > desFileSize * 1024) {
ByteArrayInputStream inputStream = new ByteArrayInputStream(imageBytes);
ByteArrayOutputStream outputStream = new ByteArrayOutputStream(imageBytes.length);
Thumbnails.of(inputStream)
.scale(accuracy)
.outputQuality(accuracy)
.toOutputStream(outputStream);
//图片压缩后的大小
imageBytes = outputStream.toByteArray();
}
log.info("【图片压缩】imageId={} | 图片原大小={}kb | 压缩后大小={}kb",
imageId, srcSize / 1024, imageBytes.length / 1024);
} catch (Exception e) {
log.error("【图片压缩】msg=图片压缩失败!", e);
}
return imageBytes;
}
/**
* 自动调节精度(经验数值)
*
* @param size 源图片大小
* @return 图片压缩质量比
*/
private static double getAccuracy(long size) {
double accuracy;
if (size < 900) {
accuracy = 0.85;
} else if (size < 2047) {
accuracy = 0.6;
} else if (size < 3275) {
accuracy = 0.44;
} else {
accuracy = 0.4;
}
return accuracy;
}
}
写一个OSS上传的工具类
public class OOSUtil {
/**
* 按照byte数组传输图片
*
* @param dir 存放的目录名称
* @param fileName 文件名称
* @param byteArray 压缩后的byte数组
* @return 图片链接
*/
public static String addFileByByteArray(String dir, String fileName, byte[] byteArray) {
OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
ObjectMetadata metadata = new ObjectMetadata();
metadata.setHeader(OSSHeaders.OSS_STORAGE_CLASS, StorageClass.Standard.toString());
//公共读
metadata.setObjectAcl(CannedAccessControlList.PublicRead);
metadata.setCacheControl("no-cache");
metadata.setHeader("Pragma", "no-cache");
metadata.setContentDisposition("inline;filename=" + fileName);
metadata.setContentType(getcontentType(fileName.substring(fileName.lastIndexOf("."))));
try {
fileName = dir + "/" + fileName;
ossClient.putObject(bucketName, fileName, new ByteArrayInputStream(byteArray), metadata);
} catch (Exception e) {
return null;
} finally {
ossClient.shutdown();
}
return "https://XXX-oos.XXX.XXX/" + fileName;//自己绑定OSS的域名
}
/**
* 判断OSS服务文件上传时文件的类型contentType
*
* @param FilenameExtension 文件后缀
* @return String
*/
public static String getcontentType(String FilenameExtension) {
if (".bmp".equalsIgnoreCase(FilenameExtension)) {
return "image/bmp";
}
if (".gif".equalsIgnoreCase(FilenameExtension)) {
return "image/gif";
}
if (".jpeg".equalsIgnoreCase(FilenameExtension) ||
".jpg".equalsIgnoreCase(FilenameExtension)) {
return "image/jpeg";
}
if (".html".equalsIgnoreCase(FilenameExtension)) {
return "text/html";
}
if (".txt".equalsIgnoreCase(FilenameExtension)) {
return "text/plain";
}
if (".vsd".equalsIgnoreCase(FilenameExtension)) {
return "application/vnd.visio";
}
if (".pptx".equalsIgnoreCase(FilenameExtension) ||
".ppt".equalsIgnoreCase(FilenameExtension)) {
return "application/vnd.ms-powerpoint";
}
if (".docx".equalsIgnoreCase(FilenameExtension) ||
".doc".equalsIgnoreCase(FilenameExtension)) {
return "application/msword";
}
if (".xml".equalsIgnoreCase(FilenameExtension)) {
return "text/xml";
}
if (".png".equalsIgnoreCase(FilenameExtension)) {
return "image/png";
}
return "image/jpg";
}
}
自己写一个测试方法:
@Test
void testByteArrays() throws IOException {
//1. 得到byte数组
byte[] bytes = FileUtils.readFileToByteArray(new File("C:\\Users\\Lenovo\\Desktop\\earth.png"));
long l = System.currentTimeMillis();
String userId = "3";
//2. 调用方法得到压缩后的byte数组
bytes = CompressionUtil.compressPicForScale(bytes, 300, userId);// 图片小于300kb
System.out.println("压缩花费时间为:"+(System.currentTimeMillis() - l));
//TODO 注意文件的后缀
//上传压缩后的数组
String url = OOSUtil.addFileByByteArray("carry_head_portrait", userId + ".png", bytes);
System.out.println(url);
//也可以用下面这两个方法
// byte[] bytes = CompressionUtil.streamToBytesAndCompression(inputStream, userId);
//url = OOSUtil.addFileByByteArray("carry_head_portrait", userId + suffix, bytes);
}
这样我们执行后在OSS控制台就可以看到结果了。
原来我的图片是4.13MB,压缩后是198.962KB,压缩的时间是2s多,说明压缩效果还是不错的。