JPG&PNG图片压缩java实现
Posted 零度anngle
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JPG&PNG图片压缩java实现相关的知识,希望对你有一定的参考价值。
最近项目中有一个需求是关于图片处理的,其实关于图片处理java的BufferedImage类基本上已经可以处理绝大多数需求,但是关于png图片的压缩遇到一点小的阻碍,我们知道png图片与JPG图片最大的区别就是可以保存为透明背景的图片,JPEG就不可以,jpeg是一种有损压缩的图片格式。png是可以转换成JPEG的,但是透明像素会变成白色的,而且图像信息会丢失一部分。png图片压缩起来比较困难。下面给出已经在项目中使用的静态方法实现这些需求。
1、图片文件生成BufferedImage对象:
/**
* @param file 图片
* @return boolean true:符合要求
* @description 图片文件转化为BufferedImage
*/
public static BufferedImage fileToBufferedImage(File file) throws IOException
if (!file.exists())
return null;
BufferedImage bufferedImage = ImageIO.read(file);
return bufferedImage;
/**
* @param fileByteArray
* @return BufferedImage
* @throws IOException
* @description 图片文件字节数组转化为BufferedImage
*/
public static BufferedImage fileToBufferedImage(byte[] fileByteArray) throws IOException
if (fileByteArray == null || fileByteArray.length == 0)
return null;
ByteArrayInputStream stream = new ByteArrayInputStream(fileByteArray);
BufferedImage bufferedImage = ImageIO.read(stream);
return bufferedImage;
2、BufferedImage对象生成图片文件:有两个写法方式:1-简单方式,2-支持高质量压缩的方式
/**
* bufferedImage 转化为文件-简单方式
* @param bufferedImage
* @param destFile 获取目标路径
* @param ext 图片的格式:jpg/png
* @throws IOException
*/
public static void bufferedImageToFile1(BufferedImage bufferedImage, String destFile, String ext) throws IOException
//使用ImageIO的方法进行输出,记得关闭资源
OutputStream out = new FileOutputStream(destFile);
ImageIO.write(bufferedImage, ext, out);
out.close();
/**
* bufferedImage 转化为文件-高质量支持压缩的方式
* @param bufferedImage
* @param destFile 获取目标路径
* @param ext 图片的格式:jpg/png
* @throws IOException
*/
public static void bufferedImageToFile2(BufferedImage bufferedImage, String destFile, String ext, float quality) throws IOException
Iterator<ImageWriter> imageWriterIter = ImageIO.getImageWritersByFormatName(ext);
if (imageWriterIter.hasNext())
ImageWriter writer = imageWriterIter.next();
ImageWriteParam param = writer.getDefaultWriteParam();
param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
param.setCompressionQuality(quality); //质量0-1.0
File file = new File(destFile);
FileImageOutputStream out = new FileImageOutputStream(file);
writer.setOutput(out);
writer.write(null, new IIOImage(bufferedImage, null, null), param);
out.close();
writer.dispose();
3、上面的压缩对于jpg和png图片,因为使用高质量的像素,会导致图片精度很高,图片比较大,现在提供对于jpg和png的图片的压缩代码
对于jpg图片,我们不断降低压缩质量会较大幅度的降低图片大小,因为jpg图片是有损压缩,质量会降低的比较大,参考代码如下:
/**
* bufferedImage 目标将图片压缩到500KB以下,最多压缩5次
* @param bufferedImage
* @param ext 图片的格式
* @param quality 默认1.0
* @throws IOException
*/
public static byte[] bufferedImageToFileByte2Less500K(String tempFilePath, BufferedImage bufferedImage, String ext, float quality) throws IOException
Iterator<ImageWriter> imageWriterIter = ImageIO.getImageWritersByFormatName(ext);
if (imageWriterIter.hasNext())
ImageWriter writer = imageWriterIter.next();
ImageWriteParam param = writer.getDefaultWriteParam();
param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
System.out.println(quality);
param.setCompressionQuality(quality); //最高质量
File file = new File(tempFilePath+ "/" + new Random().nextInt(10) + "_temp_heap_image_" + quality + "."+ext);
FileImageOutputStream out = new FileImageOutputStream(file);
writer.setOutput(out);
writer.write(null, new IIOImage(bufferedImage, null, null), param);
ByteArrayOutputStream swapStream = getByteArrayOutputStream(file);
out.close();
writer.dispose();
if(quality <=0.5f || swapStream.toByteArray().length/1024 <=500)
return swapStream.toByteArray();
else
quality = quality - 0.1f;
return bufferedImageToFileByte2Less500K(tempFilePath,bufferedImage,ext,quality);
return null;
上面的代码对于png图片,压缩的很有限,因为png是高质量图片,因此,我们要重新想办法,后来找到一个支持png压缩的工具包:OpenViewerFX,可以将png图片压缩的比较小,而且不怎么失真,代码如下:
需要引入依赖:
<dependency>
<groupId>org.jpedal</groupId>
<artifactId>OpenViewerFX</artifactId>
<version>6.6.14</version>
</dependency>
/**
* bufferedImage 转化为文件
* @param bufferedImage
* @param ext 图片的格式:png
* @throws IOException
*/
public static byte[] bufferedImageToFileByte(String tempFilePath, BufferedImage bufferedImage, String ext) throws IOException
//使用ImageIO的方法进行输出,记得关闭资源
File file = new File(tempFilePath+ "/" + new Random().nextInt(10) + "_temp_heap_image."+ext);
OutputStream out = new FileOutputStream(file);
ImageIO.write(bufferedImage, ext, out);
out.close();
ByteArrayOutputStream swapStream = getByteArrayOutputStream(file);
//对于图片是jpg或者小于500KB,就直接输出
if(ext.equalsIgnoreCase("jpg") || swapStream.toByteArray().length/1024 <=500)
return swapStream.toByteArray();
File compressOutFile=new File(tempFilePath+ "/" + new Random().nextInt(10) + "_temp_heap_image_cp."+ext);
//如果图片是png,且大于500KB,则进行压缩
PngCompressor.compress(file,compressOutFile);
swapStream = getByteArrayOutputStream(compressOutFile);
return swapStream.toByteArray();
下面再提供一些工具类:
/**
* @param file 图片
* @param imageWidth 宽
* @param imageHeight 高
* @return boolean true:符合要求
* @description 校验图片比例
*/
public static boolean checkImageScale(File file, int imageWidth, int imageHeight) throws IOException
Boolean result = false;
if (!file.exists())
return false;
BufferedImage bufferedImage = ImageIO.read(file);
int width = bufferedImage.getWidth();
int height = bufferedImage.getHeight();
if (imageHeight != 0 && height != 0)
int scale1 = imageHeight / imageWidth;
int scale2 = height / width;
if (scale1 == scale2)
result = true;
return result;
/**
* @param path 图片路径
* @return java.lang.String base64字符串
* @description 将图片文件转化为字节数组字符串,并对其进行Base64编码处理
*/
public static String imgToBase64Str(String path) throws IOException
byte[] data = null;
// 读取图片字节数组
InputStream in = null;
try
in = new FileInputStream(path);
data = new byte[in.available()];
in.read(data);
finally
if (in != null)
try
in.close();
catch (IOException e)
e.printStackTrace();
//返回Base64编码过的字节数组字符串
return Base64.encodeBase64String(data);
/**
* 按比例对图片进行缩放
* @param scale 图片根据比例缩放
* @throws IOException
*/
public static BufferedImage zoomByScale(BufferedImage bufferedImage, double scale) throws IOException
//获取图片的长和宽
int width = bufferedImage.getWidth();
int height = bufferedImage.getHeight();
//获取缩放后的长和宽
int _width = (int) (scale * width);
int _height = (int) (scale * height);
//获取缩放后的Image对象
Image _img = bufferedImage.getScaledInstance(_width, _height, Image.SCALE_DEFAULT);
//新建一个和Image对象相同大小的画布:BufferedImage.TYPE_INT_ARGB
BufferedImage image = new BufferedImage(_width, _height, BufferedImage.TYPE_INT_ARGB);
//获取画笔
Graphics2D graphics = image.createGraphics();
//将Image对象画在画布上,最后一个参数,ImageObserver:接收有关 Image 信息通知的异步更新接口,没用到直接传空
graphics.drawImage(_img, 0, 0, null);
//释放资源
graphics.dispose();
return image;
/**
* png -支持图片背景透明
* 图片指定长和宽对图片进行缩放
* @param width 长
* @param height 宽
* @throws IOException
*/
public static BufferedImage zoomBySize(BufferedImage bufferedImage, int width, int height)
//与按比例缩放的不同只在于,不需要获取新的长和宽,其余相同.
Image _img = bufferedImage.getScaledInstance(width, height, Image.SCALE_DEFAULT);
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
Graphics2D graphics = image.createGraphics();
graphics.drawImage(_img, 0, 0, null);
graphics.dispose();
return image;
/**
* @param background 背景
* @param foreground 前景
* @param x 前景x坐标
* @param y 前景y坐标
* @return
* @description 将前景图片合成到背景图上
*/
public static BufferedImage compose(BufferedImage background, BufferedImage foreground, int x, int y)
try
Graphics2D g = background.createGraphics();
g.drawImage(foreground, x, y, foreground.getWidth(), foreground.getHeight(), null);
g.dispose();
catch (Exception e)
System.out.println(e.getMessage());
return background;
/**
* 裁剪png图片的非透明区域,使用最大x和y的边框
* @param bufferedImage
* @return
* @throws IOException
*/
public static BufferedImage getNotTransparentArea(BufferedImage bufferedImage) throws IOException
int w = bufferedImage.getWidth();
int h = bufferedImage.getHeight();
int x = 0, y = 0, width = 0, height = 0;
for (int j = 0; j < h; j++)
for (int i = 0; i < w; i++)
int dip = bufferedImage.getRGB(i, j);
if ((dip & 0xff000000) != 0)
if (x == 0 || i < x)
x = i;
if (y == 0 || j < y)
y = j;
if (width == 0 || i > width)
width = i;
if (height == 0 || j > height)
height = j;
bufferedImage = bufferedImage.getSubimage(x - 1, y - 1, width - x + 1, height - y + 1);
return bufferedImage;
以上是关于JPG&PNG图片压缩java实现的主要内容,如果未能解决你的问题,请参考以下文章