今天给大家分享已个自己博客在用的图片压缩的一个工具类,压缩效果挺不错的。
import com.sun.image.codec.jpeg.JPEGCodec;
import com.sun.image.codec.jpeg.JPEGEncodeParam;
import com.sun.image.codec.jpeg.JPEGImageEncoder;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.multipart.MultipartFile;
import javax.imageio.ImageIO;
import javax.imageio.ImageReadParam;
import javax.imageio.ImageReader;
import javax.imageio.stream.ImageInputStream;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Iterator;
/**
* @className: ImageUtil
* @description: 图片压缩工具类
* @author: xiaofei
* @create: 2020年01月15日
*/
@Slf4j
public class ImageUtil {
/**
* 图片文件读取
*
* @param file 文件
* @return 结果
*/
private static BufferedImage InputImage(MultipartFile file) throws RuntimeException{
BufferedImage srcImage = null;
FileInputStream in = null;
try {
// 构造BufferedImage对象
srcImage = ImageIO.read(file.getInputStream());
} catch (IOException e) {
log.error("读取图片文件出错!", e);
throw new RuntimeException();
} finally {
if (in != null) {
try {
in.close();
} catch (IOException e) {
log.error("读取图片文件关闭流出错!", e);
}
}
}
return srcImage;
}
/**
* 将图片按照指定的图片尺寸、图片质量压缩
*
* @param file :源图片路径
* @param outImgPath :输出的压缩图片的路径
* @param new_w :压缩后的图片宽
* @param new_h :压缩后的图片高
* @param per :图片质量压缩
*/
public static void resize(MultipartFile file
, String outImgPath
, int new_w
, int new_h
, float per) {
// 得到图片
BufferedImage src = InputImage(file);
int old_w = src.getWidth();
// 得到源图宽
int old_h = src.getHeight();
// 得到源图长
// 根据原图的大小生成空白画布
BufferedImage tempImg = new BufferedImage(old_w, old_h,
BufferedImage.TYPE_INT_RGB);
// 在新的画布上生成原图的缩略图
Graphics2D g = tempImg.createGraphics();
g.setColor(Color.white);
g.fillRect(0, 0, old_w, old_h);
g.drawImage(src, 0, 0, old_w, old_h, Color.white, null);
g.dispose();
BufferedImage newImg = new BufferedImage(new_w, new_h,
BufferedImage.TYPE_INT_RGB);
newImg.getGraphics().drawImage(
tempImg.getScaledInstance(new_w, new_h, Image.SCALE_SMOOTH), 0,
0, null);
// 调用方法输出图片文件
outImage(outImgPath, newImg, per);
}
/**
* <b>
* 指定长或者宽的最大值来压缩图片
* 推荐使用此方法
* </b>
*
* @param file :源图片路径
* @param outImgPath :输出的压缩图片的路径
* @param maxLength :长或者宽的最大值
* @param per :图片质量
*/
public static void resize(MultipartFile file
, String outImgPath
, int maxLength
, float per) {
// 得到图片
BufferedImage src = InputImage(file);
int old_w = src.getWidth();
// 得到源图宽
int old_h = src.getHeight();
// 得到源图长
int new_w = 0;
// 新图的宽
int new_h = 0;
// 新图的长
BufferedImage tempImg = new BufferedImage(old_w
, old_h
, BufferedImage.TYPE_INT_RGB);
Graphics2D g = tempImg.createGraphics();
g.setColor(Color.white);
// 从原图上取颜色绘制新图
g.fillRect(0, 0, old_w, old_h);
g.drawImage(src, 0, 0, old_w, old_h, Color.white, null);
g.dispose();
// 根据图片尺寸压缩比得到新图的尺寸
if (old_w > old_h) {
// 图片要缩放的比例
new_w = maxLength;
new_h = (int) Math.round(old_h * ((float) maxLength / old_w));
} else {
new_w = (int) Math.round(old_w * ((float) maxLength / old_h));
new_h = maxLength;
}
BufferedImage newImg = new BufferedImage(new_w, new_h,
BufferedImage.TYPE_INT_RGB);
newImg.getGraphics().drawImage(
tempImg.getScaledInstance(new_w, new_h, Image.SCALE_SMOOTH), 0,
0, null);
// 调用方法输出图片文件
outImage(outImgPath, newImg, per);
}
/**
* 将图片压缩成指定宽度,高度等比例缩放
*
* @param file :源图片路径
* @param outImgPath :输出的压缩图片的路径
* @param width :长或者宽的最大值
* @param per :图片质量
*/
public static void resizeFixedWidth(MultipartFile file
, String outImgPath
, int width
, float per) {
// 得到图片
BufferedImage src = InputImage(file);
int old_w = src.getWidth();
// 得到源图宽
int old_h = src.getHeight();
// 得到源图长
int new_w = 0;
// 新图的宽
int new_h = 0;
// 新图的长
BufferedImage tempImg = new BufferedImage(old_w, old_h,
BufferedImage.TYPE_INT_RGB);
Graphics2D g = tempImg.createGraphics();
g.setColor(Color.white);
// 从原图上取颜色绘制新图
g.fillRect(0, 0, old_w, old_h);
g.drawImage(src, 0, 0, old_w, old_h, Color.white, null);
g.dispose();
// 根据图片尺寸压缩比得到新图的尺寸
if (old_w > old_h) {
// 图片要缩放的比例
new_w = width;
new_h = (int) Math.round(old_h * ((float) width / old_w));
} else {
new_w = (int) Math.round(old_w * ((float) width / old_h));
new_h = width;
}
BufferedImage newImg = new BufferedImage(new_w, new_h,
BufferedImage.TYPE_INT_RGB);
newImg.getGraphics().drawImage(
tempImg.getScaledInstance(new_w, new_h, Image.SCALE_SMOOTH), 0,
0, null);
// 调用方法输出图片文件
outImage(outImgPath, newImg, per);
}
/**
* 图片剪切工具方法
*
* @param srcfile 源图片
* @param outfile 剪切之后的图片
* @param x 剪切顶点 X 坐标
* @param y 剪切顶点 Y 坐标
* @param width 剪切区域宽度
* @param height 剪切区域高度
* @throws IOException
*/
public static void cut(File srcfile
, File outfile
, int x
, int y
, int width
, int height) throws IOException {
FileInputStream is = null;
ImageInputStream iis = null;
try {
// 读取图片文件
is = new FileInputStream(srcfile);
/*
* 返回包含所有当前已注册 ImageReader 的 Iterator,这些 ImageReader 声称能够解码指定格式。
* 参数:formatName - 包含非正式格式名称 .(例如 "jpeg" 或 "tiff")等 。
*/
Iterator<ImageReader> it = ImageIO.getImageReadersByFormatName("jpg");
ImageReader reader = it.next();
// 获取图片流
iis = ImageIO.createImageInputStream(is);
/*
* <p>iis:读取源.true:只向前搜索 </p>.将它标记为 ‘只向前搜索’。
* 此设置意味着包含在输入源中的图像将只按顺序读取,可能允许 reader 避免缓存包含与以前已经读取的图像关联的数据的那些输入部分。
*/
reader.setInput(iis, true);
/*
* <p>描述如何对流进行解码的类<p>.用于指定如何在输入时从 Java Image I/O
* 框架的上下文中的流转换一幅图像或一组图像。用于特定图像格式的插件 将从其 ImageReader 实现的
* getDefaultReadParam 方法中返回 ImageReadParam 的实例。
*/
ImageReadParam param = reader.getDefaultReadParam();
/*
* 图片裁剪区域。Rectangle 指定了坐标空间中的一个区域,通过 Rectangle 对象
* 的左上顶点的坐标(x,y)、宽度和高度可以定义这个区域。
*/
Rectangle rect = new Rectangle(x, y, width, height);
// 提供一个 BufferedImage,将其用作解码像素数据的目标。
param.setSourceRegion(rect);
/*
* 使用所提供的 ImageReadParam 读取通过索引 imageIndex 指定的对象,并将 它作为一个完整的
* BufferedImage 返回。
*/
BufferedImage bi = reader.read(0, param);
// 保存新图片
ImageIO.write(bi, "jpg", outfile);
} finally {
if (is != null) {
is.close();
}
if (iis != null) {
iis.close();
}
}
}
/**
* 将图片文件输出到指定的路径,并可设定压缩质量
*
* @param outImgPath 输出图片地址
* @param newImg 新图片
* @param per 图片质量:
* 一些准则:
* 0.75高质量 0.5中等质量 0.25低质量
* 参数: 质量 0.0-1.0 设置所需的质量级别。
*/
private static void outImage(String outImgPath
, BufferedImage newImg
, float per) {
// 判断输出的文件夹路径是否存在,不存在则创建
File file = new File(outImgPath);
if (!file.getParentFile().exists()) {
file.getParentFile().mkdirs();
}
// 输出到文件流
FileOutputStream fos = null;
try {
fos = new FileOutputStream(outImgPath);
JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(fos);
JPEGEncodeParam jep = JPEGCodec.getDefaultJPEGEncodeParam(newImg);
// 压缩质量
jep.setQuality(per, true);
encoder.encode(newImg, jep);
fos.close();
} catch (Exception e) {
log.error("outImage: 关闭流失败" + e);
} finally {
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
log.error("outImage: 关闭流失败" + e);
}
}
}
}
/**
* 将图片按照指定的图片质量压缩
*
* @param file :图片
* @param outImgPath :输出的压缩图片的路径
* @param per :图片质量压缩
*/
public static void resize(MultipartFile file
, String outImgPath
, float per) {
// 得到图片
BufferedImage src = InputImage(file);
int old_w = src.getWidth();
// 得到源图宽
int old_h = src.getHeight();
// 得到源图长
// 根据原图的大小生成空白画布
BufferedImage tempImg = new BufferedImage(old_w, old_h,
BufferedImage.TYPE_INT_RGB);
// 在新的画布上生成原图的缩略图
Graphics2D g = tempImg.createGraphics();
g.setColor(Color.white);
g.fillRect(0, 0, old_w, old_h);
g.drawImage(src, 0, 0, old_w, old_h, Color.white, null);
g.dispose();
BufferedImage newImg = new BufferedImage(old_w, old_h,
BufferedImage.TYPE_INT_RGB);
newImg.getGraphics().drawImage(
tempImg.getScaledInstance(old_w, old_h, Image.SCALE_SMOOTH), 0,
0, null);
// 调用方法输出图片文件
outImage(outImgPath, newImg, per);
}
/**
* 获取远程网络图片压缩并上传
*
* @param imageURL 远程图片的url
* @param outImgPath 输出图片地址
* @param per 图片质量
*/
public static void getImgByUrl(String imageURL, String outImgPath, float per) {
URL url = null;
InputStream is = null;
BufferedImage src = null;
try {
url = new URL(imageURL);
is = url.openStream();
src = ImageIO.read(is);
// 压缩
int old_w = src.getWidth();
// 得到源图宽
int old_h = src.getHeight();
// 得到源图长
// 根据原图的大小生成空白画布
BufferedImage tempImg = new BufferedImage(old_w, old_h,
BufferedImage.TYPE_INT_RGB);
// 在新的画布上生成原图的缩略图
Graphics2D g = tempImg.createGraphics();
g.setColor(Color.white);
g.fillRect(0, 0, old_w, old_h);
g.drawImage(src, 0, 0, old_w, old_h, Color.white, null);
g.dispose();
BufferedImage newImg = new BufferedImage(old_w, old_h,
BufferedImage.TYPE_INT_RGB);
newImg.getGraphics().drawImage(
tempImg.getScaledInstance(old_w, old_h, Image.SCALE_SMOOTH), 0,
0, null);
// 调用方法输出图片文件
outImage(outImgPath, newImg, 0.75F);
} catch (MalformedURLException e) {
log.error("getRemoteBufferedImage: " + imageURL + ",无效:" + e);
} catch (IOException e) {
log.error("getRemoteBufferedImage: " + imageURL + ",读取失败:" + e);
} finally {
try {
if (is != null) {
is.close();
}
} catch (IOException e) {
log.error("getRemoteBufferedImage: " + imageURL + ",流关闭异常:" + e);
}
}
}
}
如果使用以上的工具类打包出现以下错误:
JDK1.8 编译时提示 程序包com.sun.image.codec.jpeg不存在
解决办法:
在pom文件中build -> plugins 中加入以下配置就可以了
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<encoding>UTF-8</encoding>
<compilerArguments>
<verbose />
<bootclasspath>${java.home}\lib\rt.jar${path.separator}${java.home}\lib\jce.jar${path.separator}</bootclasspath>
</compilerArguments>
</configuration>
</plugin>