详解Java实现批量压缩图片裁剪压缩多种尺寸缩略图一键批量上传图片
作者:guobinhui
10万+IT人都在关注的图片批量压缩上传方案(完整案例+代码)
背景需求:为了客户端访问图片资源时,加载图片更流畅,体验更好,通常不会直接用原图路径,需要根据不同的场景显示不同规格的缩略图,根据商品关键属性,能够获取到图片不同尺寸规格的图片路径,并且能根据不同缩略图直观看到商品的关键属性,需要写一个Java小工具把本地磁盘中的图片资源一键上传至分布式FastDFS文件服务器,并把图片信息存入本地数据库,PC端或者客户端查询商品时,就可以根据商品的业务属性。比如根据productId就能把商品相关的不同尺寸规格的图片都获取到,页面渲染图片资源时,不同的场景,直接通过文件服务器的IP+存储路径,可以在线预览。
示例:商品id为1001的主图原图1001.jpg,大小为800×800(px),在本案例中解析为1001-50×50.jpg,1001-100×100.jpg,1001-200×200.jpg,1001-400×400.jpg,解析后连同原图就是5种尺寸规格的图片。前端就能直观的根据屏幕大小,业务场景等因素使用不同的图片。
实现思路:先把本地磁盘目录中的所有图片资源通过IO流读出来,读到内存中,然后对图片的名称根据定义好的业务规则解析,生成不同的图片名,然后对原图进行不同规格的解析压缩处理,以及图片资源的上传和图片信息的批量保存至数据库。
常用的压缩方案有下面2种:
方案一:对原图进行按照指定存储空间的压缩,比如原图100Kb,压缩至10Kb
方案二:对原图进行指定宽高大小的压缩,比如原图800*800,压缩至100*100
准备工作:封装一个文件流操作的通过工具类,如下:
package com.demo.utils; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.util.ArrayList; import java.util.List; import org.apache.tomcat.util.codec.binary.Base64; /** * 创建时间:2019年3月13日 下午9:02:32 * 项目名称:shsc-batchUpload-server * 类说明:文件流工具类 * @author guobinhui * @since JDK 1.8.0_51 */ public class FileUtils { /* * 读取本地物理磁盘目录里的所有文件资源到程序内存 */ public static List<File> readFiles(String fileDir) { File dirPath = new File(fileDir); //用listFiles()获得子目录和文件 File[] files = dirPath.listFiles(); List<File> list1 = new ArrayList<File>(); for (int i = 0; i < files.length; i++) { File file = files[i]; if (!file.isDirectory()) { list1.add(files[i]); } } System.out.println("目录图片数量为:"+list1.size()); return list1; } /* * File文件流转为Base64的字符串流 * 注意:通过前端页面上传图片时,用 MultipartFile文件流可以接收图片并上传,MultipartFile流有很丰富的方法 * 本案例通过后台小工具上传,需要把图片资源的文件流转为Base64格式的流才可以上传 */ public static String getBase64(File file) { FileInputStream fis = null; String base64String = null; try { fis = new FileInputStream(file); byte[] buff = new byte[fis.available()]; fis.read(buff); base64String = Base64.encodeBase64String(buff); } catch (FileNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } finally{ if(fis != null){ try { fis.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } return base64String; } /** * 将File文件流转为字节数组 * @param file * @return */ public static byte[] getByte(File file){ byte[] bytes = null; try { FileInputStream fis = new FileInputStream(file); bytes = new byte[fis.available()]; fis.read(bytes); fis.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return bytes; } /** * 将字节输出流写到指定文件 * @param os * @param file */ public static void writeFile(ByteArrayOutputStream os, File file){ FileOutputStream fos = null; try { byte[] bytes = os.toByteArray(); if (file.exists()) { file.delete(); } fos = new FileOutputStream(file); fos.write(bytes); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { try { fos.close(); } catch (IOException e) { e.printStackTrace(); } } } }
封装一个压缩图片处理类
package com.demo.mapper.entity; import java.awt.Image; import java.awt.geom.AffineTransform; import java.awt.image.AffineTransformOp; import java.awt.image.BufferedImage; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import javax.imageio.ImageIO; /** * 创建时间:2019年3月13日 下午3:35:05 * 项目名称:shsc-batchUpload-server * 类说明:图片压缩处理类 * @author guobinhui * @since JDK 1.8.0_51 */ public class ImgCompress { private Image img; private int width; private int height; /** * 构造函数 */ public ImgCompress(String filePath) throws IOException { File file = new File(filePath);// 读入文件 img = ImageIO.read(file); // 构造Image对象 width = img.getWidth(null); // 得到源图宽 height = img.getHeight(null); // 得到源图长 } public Image getImg() { return img; } public void setImg(Image img) { this.img = img; } public int getWidth() { return width; } public void setWidth(int width) { this.width = width; } public int getHeight() { return height; } public void setHeight(int height) { this.height = height; } public void reSize(int w, int h,File file,String dir) throws IOException { // SCALE_SMOOTH 的缩略算法 生成缩略图片的平滑度的 优先级比速度高 生成的图片质量比较好,但是速度慢 BufferedImage tag = new BufferedImage(50,50,BufferedImage.TYPE_INT_RGB ); Image img = ImageIO.read(file); Image image = img.getScaledInstance(w, h, Image.SCALE_SMOOTH); tag.getGraphics().drawImage(image,50, 50, null); // 绘制缩小后的图 // 将输入文件转换为字节数组 byte[] bytes = FileUtils.getByte(file); // 构造输入输出字节流 ByteArrayInputStream is = new ByteArrayInputStream(bytes); ByteArrayOutputStream os = new ByteArrayOutputStream(); double rate = w/800;//缩放比率 try { // 处理图片 zoomImage(is,os,rate); } catch (Exception e) { e.printStackTrace(); } // 将字节输出流写入文件 FileUtils.writeFile(os,new File(dir+"/"+file.getName())); } public void zoomImage(InputStream is, OutputStream os,double Rate) throws Exception { BufferedImage bufImg = ImageIO.read(is); AffineTransformOp ato = new AffineTransformOp(AffineTransform.getScaleInstance(Rate,Rate), null); BufferedImage bufferedImage = ato.filter(bufImg, null); ImageIO.write(bufferedImage, "jpg", os); } }
方案一具体实现过程:
package com.demo.controller; import java.awt.Color; import java.awt.Graphics; import java.awt.Image; import java.awt.image.BufferedImage; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import javax.imageio.ImageIO; import org.apache.tomcat.util.codec.binary.Base64; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; import com.demo.mapper.entity.AttachmentModel; import com.demo.mapper.entity.ImgCompress; import com.demo.mapper.entity.ProductPic; import com.demo.service.IFileService; import com.demo.utils.FileUtils; import com.shsc.framework.common.ResultInfo; /** * 创建时间:2019年3月8日 下午3:03:56 * 项目名称:shsc-batchUpload-server * 类说明:图片批量压缩上传 * @author guobinhui * @since JDK 1.8.0_51 */ @RestController @RequestMapping(value="/file") public class FileController { @Autowired private IFileService fileServiceImpl; @RequestMapping("/test") @ResponseBody public String test() { //原始图片目录 String originalFileDir = "D:/pics/pic1"; List <File> originalFileList = readFiles(originalFileDir); Iterator<File> it = originalFileList.iterator(); //压缩后的缩略图目录 String thumbnailDir = "D:/uploadBaseDir/productPic/20190313/thumbnail"; long startWrite = System.currentTimeMillis(); while(it.hasNext()){ File file = (File)it.next(); try { ImgCompress img = new ImgCompress(file.getPath()); img.reSize(50, 50, file, thumbnailDir); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); return "上传失败!"; } } long endWrite = System.currentTimeMillis(); System.out.println("批量上传文件共计耗时:" +(endWrite-startWrite)/1000+"秒" ); return "<h1 style='color:red;'>批量上传文件成功,非常棒,压缩上传文件总数量为:"+num+",共计耗时"+(endWrite-startWrite)/1000+"秒</h1>"; } }
最后在浏览器上访问该接口或者把该接口放在main方法里run,效果如下:
方案二具体实现过程:
@RequestMapping("/upload") @ResponseBody public String upload(){ //win环境原始文件目录 String originalFileDir = "D:/pics/pic1"; System.out.println("读磁盘文件开始"); long startRead = System.currentTimeMillis(); List <File> originalFileList = readFiles(originalFileDir); long endRead = System.currentTimeMillis(); System.out.println("读磁盘文件结束"); System.out.println("读取磁盘文件共计耗时:" +(endRead-startRead)+"毫秒" ); Iterator<File> it = originalFileList.iterator(); System.out.println("压缩拷贝文件开始"); long startWrite = System.currentTimeMillis(); // Integer size = 500;//每500个图片批量插入一次 // Integer i = 0; String productNumber = null; String thumbnailDir = "D:/uploadBaseDir/productPic/20190313/thumbnail"; String base64 = null; String new50PicName = ""; String new100PicName = ""; String new200PicName = ""; String new400PicName = ""; List <ProductPic> picList = new ArrayList<ProductPic>(); int picType; List <Integer> sizeList = new ArrayList<Integer>(); sizeList.add(0,50); sizeList.add(1,100); sizeList.add(2,200); sizeList.add(3,400); while(it.hasNext()){ File file = (File)it.next(); System.out.println("原始文件路径为:"+file.getPath()); String originalFileName= file.getName(); String prefixName = originalFileName.substring(0,originalFileName.lastIndexOf(".")); String ext = originalFileName.substring(originalFileName.lastIndexOf(".")); byte[] buff = FileUtils.getByte(file); ByteArrayInputStream is = new ByteArrayInputStream(buff); ByteArrayOutputStream os = null; BufferedImage BI = null; base64 = getBase64(file); ResultInfo<?> r = fileServiceImpl.uploadBase64(base64,originalFileName); AttachmentModel att = (AttachmentModel)r.getData(); if(originalFileName.indexOf('-') == -1) { picType = 1; productNumber = prefixName; }else { picType = 2; productNumber = originalFileName.substring(0,originalFileName.lastIndexOf("-")); } if(r.isSuccess()) { ProductPic pic = new ProductPic(); BeanUtils.copyProperties(att, pic); pic.getPicName(); pic.setProductId(productNumber); pic.setPicType(picType); picList.add(pic); } if(originalFileName.indexOf('-') == -1) {//不带'-'的是商品主图 productNumber = prefixName; new50PicName = productNumber+'-'+ "50×50"+ext; new100PicName = productNumber+'-'+ "100×100"+ext; new200PicName = productNumber+'-'+ "200×200"+ext; new400PicName = productNumber+'-'+ "400×400"+ext; }else { productNumber = originalFileName.substring(0,originalFileName.lastIndexOf("-")); new50PicName = originalFileName.substring(0,originalFileName.lastIndexOf("."))+'-'+ "50×50"+ext; new100PicName = originalFileName.substring(0,originalFileName.lastIndexOf("."))+'-'+ "100×100"+ext; new200PicName = originalFileName.substring(0,originalFileName.lastIndexOf("."))+'-'+ "200×200"+ext; new400PicName = originalFileName.substring(0,originalFileName.lastIndexOf("."))+'-'+ "400×400"+ext; } try { File f = null; BI = ImageIO.read(is); for (int i = 0; i < sizeList.size(); i++) { os = new ByteArrayOutputStream(); Image image = BI.getScaledInstance(sizeList.get(i),sizeList.get(i), Image.SCALE_SMOOTH); BufferedImage tag = new BufferedImage(sizeList.get(i),sizeList.get(i),BufferedImage.TYPE_INT_RGB); Graphics g = tag.getGraphics(); g.setColor(Color.RED); g.drawImage(image, 0, 0, null); //绘制处理后的图 g.dispose(); ImageIO.write(tag, "jpg", os); if(sizeList.get(i) == 50) { FileUtils.writeFile(os,new File(thumbnailDir+"/"+new50PicName)); f = new File(thumbnailDir+"/"+new50PicName); }else if(sizeList.get(i) == 100) { FileUtils.writeFile(os,new File(thumbnailDir+"/"+new100PicName)); f = new File(thumbnailDir+"/"+new100PicName); }else if(sizeList.get(i) == 200) { FileUtils.writeFile(os,new File(thumbnailDir+"/"+new200PicName)); f = new File(thumbnailDir+"/"+new200PicName); }else if(sizeList.get(i) == 400) { FileUtils.writeFile(os,new File(thumbnailDir+"/"+new400PicName)); f = new File(thumbnailDir+"/"+new400PicName); } base64 = getBase64(f); ResultInfo<?> rr = fileServiceImpl.uploadBase64(base64,f.getName()); if(rr.isSuccess()) { AttachmentModel atta = (AttachmentModel)rr.getData(); if(atta.getPicName().indexOf('-') == -1) {//不带'-'的是商品主图 picType = 1; }else if(atta.getPicName().indexOf("-1.") != -1 || atta.getPicName().indexOf("-2.") != -1 || atta.getPicName().indexOf("-3.") != -1 || atta.getPicName().indexOf("-4.") != -1) { picType = 2; }else if((atta.getPicName().indexOf("-1-") == -1 ||atta.getPicName().indexOf("-2-") == -1 ||atta.getPicName().indexOf("-3-") == -1 ||atta.getPicName().indexOf("-4-") == -1) && atta.getPicName().indexOf("-") != -1) { picType = 3; }else { picType = 4; } ProductPic pic = new ProductPic(); BeanUtils.copyProperties(atta, pic); pic.getPicName(); pic.setProductId(productNumber); pic.setPicType(picType); picList.add(pic); } } } catch (Exception e1) { // TODO Auto-generated catch block e1.printStackTrace(); } } int num = fileServiceImpl.insertPics(picList); if(num > 0) { long endWrite = System.currentTimeMillis(); System.out.println("批量上传文件共计耗时:" +(endWrite-startWrite)/1000+"秒" ); return "<h1 style='color:red;'>批量上传文件成功,非常棒,压缩上传文件总数量为:"+num+",共计耗时"+(endWrite-startWrite)/1000+"秒</h1>"; } return "批量上传文件失败!"; }
以上所述是小编给大家介绍的Java实现批量压缩图片裁剪压缩多种尺寸缩略图一键批量上传图片详解整合,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对脚本之家网站的支持!