java实现图片分辨率压缩、图片软化、jpg质量压缩

tech2023-12-02  37

最近遇见个需求,需要压缩图片,但是很多涉及到的方法类,要么对jdk依赖比较大,要么对系统的配置有要求,经过几天的研究和测试,终于整了一个还算比较全的方案。

代码

注解1:关于根据url读取图片的方法有很多,这里解释下为什么使用new ImageIcon(new URL(url)).getImage()而不使用ImageIo.read(new URL(url)),因为ImageIo.read这个方法读取颜色空间为CMKY的图片时会报错bad sequence number

注解2:关于图片质量压缩,网上大多数方法是使用JPEGImageEncoder工具类,但是为什么我们选择ImageWriteParam呢? JPEGImageEncoder在jdk1.7以后就被移除了,并且还需要使用jre底层的内容。

package com.common.file.img; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.imageio.IIOImage; import javax.imageio.ImageIO; import javax.imageio.ImageWriteParam; import javax.imageio.ImageWriter; import javax.swing.*; import java.awt.*; import java.awt.image.BufferedImage; import java.awt.image.ColorModel; import java.awt.image.ConvolveOp; import java.awt.image.Kernel; import java.io.*; import java.net.MalformedURLException; import java.net.URL; import java.util.Iterator; /** * @author zhao * @date 2020/8/31 16:11 */ public class ImageIoUtil { private static Logger logger = LoggerFactory.getLogger(ImageIoUtil.class); private final static String jpg = "jpg"; private final static String jpeg = "jpeg"; public static void main(String[] args) { String url = "http://pics.sc.chinaz.com/files/pic/pic9/201509/apic14546.jpg"; String suffix = url .substring(url.lastIndexOf(".") + 1); compression(url,1.5,0.1f,0.5f,suffix); } /*** * TODO * @author zhao * @date 2020/9/3 10:19 * @param url 图片地址 * @param num 分辨率缩放比例,取值范围大于1 * @param quality 图片质量缩放比例,取值范围大于0小于1 * @param softenFactor 图片软化比例,取值范围大于0,小于1,小于0.1时,图片大小增加 * @param suffix 图片后缀名 * @return byte[] */ public static byte[] compression(String url, double num, float softenFactor, float quality, String suffix) { try { boolean numFlag = !"".equals(num) && num > 1; boolean softenFactorFlag = !"".equals(softenFactor) && softenFactor > 0 && softenFactor < 1; boolean qualityFlag = !"".equals(quality) && quality > 0 && quality < 1; //判断是否是jpeg或者jpg图片,其他类型不支持质量压缩,至少我没找到方法 boolean suffixFlag = jpeg.equals(suffix) || jpg.equals(suffix); // 描述请见 <注解1> Image temp = new ImageIcon(new URL(url)).getImage(); int w = temp.getWidth(null); int h = temp.getHeight(null); if (numFlag) { //分辨率压缩的后的大小 h = new Double(h / num).intValue(); w = new Double(w / num).intValue(); } // 分辨率压缩 BufferedImage bimage = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB); // 将图像复制到缓冲的图像。 Graphics g = bimage.createGraphics(); g.drawImage(temp, 0, 0, w, h, Color.LIGHT_GRAY, null); g.dispose(); //如果三个值都不符合取值范围,则不进行压缩 //其实ImageIo在write时是对质量有影响的。 if (!numFlag && !softenFactorFlag && !qualityFlag) { ByteArrayOutputStream out = new ByteArrayOutputStream(); ImageIO.write(bimage, suffix, out); return out.toByteArray(); } // 软化 if (softenFactorFlag) { float[] softenArray = {0, softenFactor, 0, softenFactor, 1 - (softenFactor * 4), softenFactor, 0, softenFactor, 0}; Kernel kernel = new Kernel(3, 3, softenArray); ConvolveOp cOp = new ConvolveOp(kernel, ConvolveOp.EDGE_NO_OP, null); bimage = cOp.filter(bimage, null); } if (suffixFlag && qualityFlag) { //质量压缩 return quality(bimage, quality, suffix); } else { ByteArrayOutputStream out = new ByteArrayOutputStream(); ImageIO.write(bimage, suffix, out); return out.toByteArray(); } } catch (MalformedURLException e) { e.printStackTrace(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return null; } /*** * TODO 根据质量压缩图片,为什么选择这个方法请见<注解2> * @author zhaosongbin * @date 2020/9/3 16:51 * @param image * @param quality * @param suffix * @return byte[] */ private static byte[] quality(BufferedImage image, float quality, String suffix) { try { // 得到指定Format图片的writer,得到迭代器 Iterator iter = ImageIO .getImageWritersByFormatName(suffix); ImageWriter writer = (ImageWriter) iter.next(); // 得到指定writer的输出参数设置(ImageWriteParam ) ImageWriteParam iwp = writer.getDefaultWriteParam(); // 设置可否压缩 iwp.setCompressionMode(ImageWriteParam.MODE_EXPLICIT); // 设置压缩质量参数 iwp.setCompressionQuality(quality); iwp.setProgressiveMode(ImageWriteParam.MODE_DISABLED); ColorModel colorModel = ColorModel.getRGBdefault(); // 指定压缩时使用的色彩模式 iwp.setDestinationType(new javax.imageio.ImageTypeSpecifier(colorModel, colorModel.createCompatibleSampleModel(16, 16))); // 开始打包图片,写入byte[] // 取得内存输出流 ByteArrayOutputStream out = new ByteArrayOutputStream(); IIOImage iIamge = new IIOImage(image, null, null); // 此处因为ImageWriter中用来接收write信息的output要求必须是ImageOutput // 通过ImageIo中的静态方法,得到byteArrayOutputStream的ImageOutput writer.setOutput(ImageIO .createImageOutputStream(out)); writer.write(null, iIamge, iwp); //根据字节流生成图片和原图做下比较,测试完注释 FileOutputStream fos = new FileOutputStream("C:/Users/zhao/Desktop/test/test.jpg"); fos.write(out.toByteArray()); fos.close(); return out.toByteArray(); } catch (IOException e) { e.printStackTrace(); } return null; } }
最新回复(0)