什么是webp格式?
WebP 格式是一种图像文件格式。
它是由谷歌开发的,旨在提供一种高效的图像压缩方式,同时保持较好的图像质量。WebP 格式具有较小的文件体积,能够在一定程度上减少网络传输的数据量,提升网页加载速度。它支持有损压缩和无损压缩两种模式。
为什么要用webp格式?
- 减小文件大小
- 能显著降低图片文件的体积,节省存储空间。
- 减少网络传输的数据量,降低服务器的带宽压力。
- 提升加载效率
- 更快的加载速度可以改善用户体验。
- 快速加载的图片能让用户在浏览时感觉更流畅。
- 保持较好质量
- 在压缩过程中能较好地保留图像的细节和质量。
话不多说,上代码
首先 spring 三板斧
引入依赖:
因为webp在java中并没有上传到maven中央仓库,只能通过jar手动上传。点我下载文件
手动依赖方案:
<!-- 图片格式转换为webp-->
<dependency>
<groupId>com.github.nintha</groupId>
<artifactId>webp-imageio-core</artifactId>
<version>0.1.3</version>
<scope>system</scope>
<systemPath>${project.basedir}/src/main/resources/libs/webp-imageio-core-0.1.3.jar</systemPath>
</dependency>
FileUtils
package cn.ideamake.file.common.utils;
import cn.hutool.core.io.FileTypeUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.stream.StreamUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.ideamake.file.aop.MockMultipartFile;
import com.luciad.imageio.webp.WebPWriteParam;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.multipart.MultipartFile;
import javax.imageio.IIOImage;
import javax.imageio.ImageIO;
import javax.imageio.ImageWriter;
import javax.imageio.stream.FileImageOutputStream;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Files;
import java.util.Date;
import java.util.UUID;
@Slf4j
public class FileUtils {
/**
* 图片文件类型转换为webp格式
* @return webp图片
*/
public static File imagesToWebp(File file){
try {
String fileType = FileTypeUtil.getType(file);
String outputWebpPath;
if (!StrUtil.equalsAny(fileType, "jpg", "png", "jpeg")) {
return null;
}
outputWebpPath = "/tmp/" + RandomUtil.randomString(32) + ".webp";
// Obtain an image to encode from somewhere
BufferedImage image = ImageIO.read(file);
// Obtain a WebP ImageWriter instance
ImageWriter writer = ImageIO.getImageWritersByMIMEType("image/webp").next();
// Configure encoding parameters
WebPWriteParam writeParam = new WebPWriteParam(writer.getLocale());
writeParam.setCompressionMode(WebPWriteParam.MODE_DEFAULT);
// Configure the output on the ImageWriter
writer.setOutput(new FileImageOutputStream(new File(outputWebpPath)));
// Encode
writer.write(null, new IIOImage(image, null, null), writeParam);
return new File(outputWebpPath);
} catch (Exception e) {
log.error("上传失败", e);
return null;
}
}
public static MultipartFile imagesToWebp(MultipartFile multipartFile) throws IOException {
File tmpFile = multipartFileToFile(multipartFile, "/tmp/multipartFileToFile"
, RandomUtil.randomString(32) + "." + FileUtil.getSuffix(multipartFile.getOriginalFilename()));
File file = imagesToWebp(tmpFile);
return file == null ? multipartFile : new MockMultipartFile(file.getName(), FileUtil.getInputStream(file));
}
/**
* MultipartFile类型文件转File
* @return File类型文件
*/
private static File multipartFileToFile(MultipartFile multipartFile, String filePath, String fileName){
File f = null;
File dir = new File(filePath);
if (!dir.exists() && !dir.isDirectory()) {
dir.mkdirs();
}
if(multipartFile.getSize() <= 0){
multipartFile = null;
} else {
try {
InputStream ins = multipartFile.getInputStream();
f = new File(filePath + fileName);
OutputStream os = Files.newOutputStream(f.toPath());
int bytesRead = 0;
byte[] buffer = new byte[8192];
while ((bytesRead = ins.read(buffer, 0, 8192)) != -1){
os.write(buffer, 0, bytesRead);
}
os.close();
ins.close();
} catch (IOException e) {
log.error("转换file文件失败:{}", e);
}
}
return f;
}
public static byte[] imagesToWebp(byte[] bytes, String fileName){
File file = imagesToWebp(FileUtil.writeBytes(bytes, "/tmp/multipartFileToFile/" + fileName));
return file == null ? bytes : FileUtil.readBytes(file);
}
}
方法可自行重载扩展。
需要返回 MultipartFile 文件格式康我 MockMultipartFile 类
/*
* Copyright 2002-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.ideamake.file.aop;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.FileCopyUtils;
import org.springframework.web.multipart.MultipartFile;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
/**
* Mock implementation of the {@link MultipartFile}
* interface.
*
*/
public class MockMultipartFile implements MultipartFile {
private final String name;
private final String originalFilename;
@Nullable
private final String contentType;
private final byte[] content;
/**
* Create a new MockMultipartFile with the given content.
* @param name the name of the file
* @param content the content of the file
*/
public MockMultipartFile(String name, @Nullable byte[] content) {
this(name, name, null, content);
}
/**
* Create a new MockMultipartFile with the given content.
* @param name the name of the file
* @param contentStream the content of the file as stream
* @throws IOException if reading from the stream failed
*/
public MockMultipartFile(String name, InputStream contentStream) throws IOException {
this(name, name, null, FileCopyUtils.copyToByteArray(contentStream));
}
/**
* Create a new MockMultipartFile with the given content.
* @param name the name of the file
* @param originalFilename the original filename (as on the client's machine)
* @param contentType the content type (if known)
* @param content the content of the file
*/
public MockMultipartFile(
String name, @Nullable String originalFilename, @Nullable String contentType, @Nullable byte[] content) {
Assert.hasLength(name, "Name must not be null");
this.name = name;
this.originalFilename = (originalFilename != null ? originalFilename : "");
this.contentType = contentType;
this.content = (content != null ? content : new byte[0]);
}
/**
* Create a new MockMultipartFile with the given content.
* @param name the name of the file
* @param originalFilename the original filename (as on the client's machine)
* @param contentType the content type (if known)
* @param contentStream the content of the file as stream
* @throws IOException if reading from the stream failed
*/
public MockMultipartFile(
String name, @Nullable String originalFilename, @Nullable String contentType, InputStream contentStream)
throws IOException {
this(name, originalFilename, contentType, FileCopyUtils.copyToByteArray(contentStream));
}
@Override
public String getName() {
return this.name;
}
@Override
public String getOriginalFilename() {
return this.originalFilename;
}
@Override
@Nullable
public String getContentType() {
return this.contentType;
}
@Override
public boolean isEmpty() {
return (this.content.length == 0);
}
@Override
public long getSize() {
return this.content.length;
}
@Override
public byte[] getBytes() {
return this.content;
}
@Override
public InputStream getInputStream() {
return new ByteArrayInputStream(this.content);
}
@Override
public void transferTo(File dest) throws IOException, IllegalStateException {
FileCopyUtils.copy(this.content, dest);
}
}
效果展示:
图片展示
webp
jpg
大小展示
webp
jpg
压缩了50% 而且还能保质保证图片效果!
本文到此结束啦,希望对你有所帮助!如果害怕下次找不到笔者关注点一点!