详解Java实现批量压缩图片裁剪压缩多种尺寸缩略图一键批量上传图片

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实现批量压缩图片裁剪压缩多种尺寸缩略图一键批量上传图片详解整合,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对我们网站的支持!

(0)

相关推荐

  • java_IO向文件中写入和读取内容代码实例

    使用java中OutStream()向文件中写入内容 package Stream; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; public class OutStreamDemo01 { public static void main(Str

  • 详解Java包装类及自动装箱拆箱

    Java包装类 基本类型 大小 包装器类型 boolean / Boolean char 16bit Boolean byte 8bit Byte short /16bit Short int 32bit Integer long 64bit Long float 32bit Float double 64bit Double void / Void Java 的包装类有两个主要的目的: Java包装类将基本数据类型的值"包装"到对象中,对基本数据类型的操作变为了对对象进行操作,从而使

  • javascript验证form表单数据的案例详解

    直接po截图和代码 下面是CheckFormDemo.html <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>验证表单的案例</title> <link rel="stylesheet" type="text/css" href="../css/body.css" rel=&q

  • 详解JAVA中的Collection接口和其主要实现的类

    Collection是最基本的集合接口,一个Collection代表一组Object,即Collection的元素(Elements).一些Collection允许相同的元素而另一些不行.一些能排序而另一些不行.Java SDK不提供直接继承自Collection的类,Java SDK提供的类都是继承自Collection的"子接口"如List和Set,详细信息可见官方文档http://tool.oschina.net/uploads/apidocs/jdk-zh/java/util/

  • Java中List add添加不同类型元素的讲解

    问题: 今天看java的list ,list后面的<> 里面可以填多种类型,但是如果不填写类型那就默认为 Object 类型. 所有我门 add 到 list 里的 数据都会被转换成 Object 类型. 而当我门再从list 中取出该数据时,就会发现数据类型已经改变. 解答 java集合中 能添加不同类型的元素其实不同类型的元素,只是地一定层次是不同元素,根本上都继承于Object类,本质上还是同一类型的元素. List<Object> list = new ArrayList&

  • Java双重检查加锁单例模式的详解

    什么是DCL DCL(Double-checked locking)被设计成支持延迟加载,当一个对象直到真正需要时才实例化: class SomeClass { private Resource resource = null; public Resource getResource() { if (resource == null) resource = new Resource(); return resource; } } 为什么需要推迟初始化?可能创建对象是一个昂贵的操作,有时在已知的运

  • 4位吸血鬼数字的java实现思路与实例讲解

    这个问题来源于Java编程思想一书,所谓"吸血鬼数字"就是指位数为偶数的数字,可以由一对数字相乘而得到,而这对数字各包含乘积的一半位数字,其中从偶数位数字中选取的数字可以任意排列.例如: 1260=21*60,1827=21*87,2187=27*81-- 先列出结果: 一共7个: 1260=21*60,1395=15*93,1435=41*35,1530=51*30,1827=87*21,2187=27*81,6880=86*80 第一种思路对所有的4位数进行穷举,假设这个4位数是a

  • Javascript的this详解

    在理解javascript的this之前,首先先了解一下作用域. 作用域分为两种: 1.词法作用域:引擎在当前作用域或者嵌套的子作用域查找具有名称标识符的变量.(引擎如何查找和在哪查找.定义过程发生在代码书写阶段) 2.动态作用域:在运行时被动态确定的作用域. 词法作用域和动态作用域的区别是:词法作用域是在写代码或定义时确定的:动态作用域是在运行时确定的. this的绑定规则 this是在调用时被绑定,取决于函数的调用位置.由此可以知道,一般情况下(非严格模式下),this都会根据函数调用(调用

  • 详解javascript函数写法大全

    1.常规写法 function fnName(){ console.log("常规写法"); } 2.匿名函数,函数保存到变量里 var myfn = function(){ console.log("匿名函数,函数保存到变量里"); } 3.如果有多个变量,可以用对象收编变量 3.1 用json对象 var fnobject1={ fn1:function(){ console.log("第一个函数"); }, fn2:function(){

  • Java ThreadLocal的设计理念与作用

    Java中的ThreadLocal类允许我们创建只能被同一个线程读写的变量.因此,如果一段代码含有一个ThreadLocal变量的引用,即使两个线程同时执行这段代码,它们也无法访问到对方的ThreadLocal变量. 如何创建ThreadLocal变量 以下代码展示了如何创建一个ThreadLocal变量: private ThreadLocal myThreadLocal = new ThreadLocal(); 我们可以看到,通过这段代码实例化了一个ThreadLocal对象.我们只需要实例

随机推荐