使用Jcrop.js和jQuery.form.js,用ImageIO等进行头像上传缩放及裁剪

首先,Java代码里带一个获取ImageReader的Iterator

    /**
     * 从网上摘抄的。
     * 返回包含所有当前已注册 ImageReader 的 Iterator,这些 ImageReader 声称能够解码指定格式。
     * 参数:postFix - 包含非正式格式名称 .(例如 "jpeg" 或 "tiff")等 。
     * 
     * @param postFix
     *            文件的后缀名
     * @author 刘各欢
     * @return
     */
    public Iterator<ImageReader> getImageReadersByFormatName(String postFix) {
        switch (postFix) {
        case "jpg":
            return ImageIO.getImageReadersByFormatName("jpg");
        case "jpeg":
            return ImageIO.getImageReadersByFormatName("jpeg");
        case "gif":
            return ImageIO.getImageReadersByFormatName("gif");
        case "bmp":
            return ImageIO.getImageReadersByFormatName("bmp");
        case "png":
            return ImageIO.getImageReadersByFormatName("png");
        default:
            return ImageIO.getImageReadersByFormatName("jpg");
        }
    }





第一步,用jQuery.form.js的ajaxSubmit()提交上传的原始图片,对图片进行缩放并返回等比例大小的图片,限制返回的图片最大尺寸为1000px X 500px


Java核心代码如下:

	/**
	 * 
	 * imgFileZoom:传入一个图片文件输入流,写入缩放后的图片到输出流
	 * 
	 * @author 刘各欢
	 * @param postFix
	 * @param in
	 * @param out
	 * @param showHeight 网页显示区域的高
	 * @param showWidth 网页显示区域的宽
	 * @return
	 * @throws IOException
	 * @since  Ver 1.1
	 */
    public Map<String,String> imgFileZoom(String postFix,InputStream in,FileOutputStream out,int showHeight,int showWidth) throws IOException{
		//FileInputStream is = null;
        ImageInputStream iis = null;
        Map<String,String> map = new HashMap<String,String>();
        try {
            // 读取图片文件
            //is = new FileInputStream(in);

            // 获取文件的后缀名
            
            System.out.println("图片格式为:" + postFix);
            /*
             * 返回包含所有当前已注册 ImageReader 的 Iterator,这些 ImageReader 声称能够解码指定格式。
             * 参数:formatName - 包含非正式格式名称 .(例如 "jpeg" 或 "tiff")等 。
             */
            Iterator<ImageReader> it = this.getImageReadersByFormatName(postFix);

            ImageReader reader = it.next();
            // 获取图片流
            iis = ImageIO.createImageInputStream(in);

            /*
             * <p>iis:读取源.true:只向前搜索 </p>.将它标记为 ‘只向前搜索’。
             * 此设置意味着包含在输入源中的图像将只按顺序读取,可能允许 reader 避免缓存包含与以前已经读取的图像关联的数据的那些输入部分。
             */
            reader.setInput(iis, true);
            int realWidth = reader.getWidth(0);
            int realHeight = reader.getHeight(0);
            
            double ratio = 1.0;
            
            if(realWidth>showWidth){
            	BigDecimal d1 = new BigDecimal(showWidth);
            	BigDecimal d2 = new BigDecimal(realWidth);
            	ratio = d1.divide(d2, 8,BigDecimal.ROUND_HALF_UP).doubleValue();
            }else if(realHeight>showHeight){
            	BigDecimal d1 = new BigDecimal(showHeight);
            	BigDecimal d2 = new BigDecimal(showHeight);
            	ratio = d1.divide(d2, 8,BigDecimal.ROUND_HALF_UP).doubleValue();
            }else{
            	ratio = 1.0;
            }
            
            BigDecimal ratioDecimal = new BigDecimal(ratio);
            BigDecimal realWidthDecimal = new BigDecimal(realWidth);
            BigDecimal realHeightDecimal = new BigDecimal(realHeight);
            BigDecimal outputWidthDecimal = BigDecimal.ONE;
            BigDecimal outputHeightDecimal = BigDecimal.ONE;
            outputWidthDecimal = realWidthDecimal.multiply(ratioDecimal);
            outputHeightDecimal = realHeightDecimal.multiply(ratioDecimal);
            int outputWidth = outputWidthDecimal.intValue();
            int outputHeight = outputHeightDecimal.intValue();
            //装入最终转换过的图片的宽高
            map.put("outputWidth", String.valueOf(outputWidth));
            map.put("outputHeight", String.valueOf(outputHeight));
            
            /*
             * 使用所提供的 ImageReadParam 读取通过索引 imageIndex 指定的对象,并将 它作为一个完整的
             * BufferedImage 返回。
             */
            BufferedImage bi = reader.read(0);

            
            /*
             * 缩放图片
             */
            Image imageSmall = bi.getScaledInstance(outputWidth, outputHeight, Image.SCALE_DEFAULT);  
            
            BufferedImage small = new BufferedImage(outputWidth, outputHeight, BufferedImage.TYPE_INT_RGB);
            
            Graphics g = small.getGraphics();
            g.drawImage(imageSmall, 0, 0, null); // 绘制缩小后的图  将Image绘制到BufferedImage中
            g.dispose();
            
            
            
            //写入新图片到输出流
            ImageIO.write(small, postFix, out);
        } finally {
            if (in != null)
                in.close();
            if (iis != null)
                iis.close();
            if (out != null)
                out.close();
        }
        return map;
    }
    
    /**
     * 
     * updateZoomTxService:对上传的头像图片进行缩放,并返回一些参数
     * 
     * @author 刘各欢
     * @param pic
     * @param req
     * @return
     * @since  Ver 1.1
     */
    public Map<String,Object> uploadZoomTx(MultipartFile pic,String uid,HttpServletRequest req){
		//从CommonInfo中读取上传文件的路径
		String pathString = CommonInfo.touxiangPath+"/zoom/";
		String fileName = "";
		Map<String,Object> map = new HashMap<String,Object>();
		
		//判断文件是否已经被获取到
		if (pic.getSize() > 0) {
			//user.setImage(pathString + pic.getOriginalFilename());
			//判断文件存储路径是否存在
			File file = new File(pathString);

			if (!file.exists() && !file.isDirectory()) {
				file.mkdirs();
			}
			try {
				String ext=pic.getOriginalFilename().substring(pic.getOriginalFilename().lastIndexOf(".")+1,pic.getOriginalFilename().length());
				fileName = System.currentTimeMillis()+uid+"."+ext;
				//创建缩放过的文件输出流
				FileOutputStream fout = new FileOutputStream(pathString + fileName );
				
				
				map.put("imgInfo",this.imgFileZoom(ext.toLowerCase(),pic.getInputStream(),fout,500,1000));
				map.put("imgUrl", fileName);
				
				if(fout!=null) 
					fout.close();
				
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		return map;
	}


返回的参数中带有缩放后的图像长宽信息,在前台js处获取到,对Jcrop进行初始化。

前台核心代码(ajaxSubmit()及成功后的触发):

		$("#uploadTxBtn").click(function(){
			var option = {  
                    type: "post",  
                    success : function(data){  
                    	zoomPicName = data['imgUrl'];
                       
                       $("#p_img").attr("src", "../../touxiang/zoom/"+data['imgUrl']);
                       $("#p_img").show();
                       $("#preview_block").show();
                       $("#p_img_preview").attr("src", "../../touxiang/zoom/"+data['imgUrl']);
                       $("#p_img").width(data['imgInfo']['outputWidth']);
                       $("#p_img").height(data['imgInfo']['outputHeight']);
                       
                       $("#uploadZoomTx").height(parseInt(data['imgInfo']['outputHeight'])+150);
                       caijian();
                   }  
                  };  
                  $("#uploadZoomTx").ajaxSubmit(option);  
		});


Jcrop相关初始化的js代码:

function caijian(){

        
        
  // Create variables (in this scope) to hold the API and image size
  var jcrop_api, boundx, boundy;
  
  $('#p_img').Jcrop({
    onChange: updatePreview,
    onSelect: updatePreview,
    aspectRatio: 1,
    setSelect: [0,0,100,100]
  },function(){
    // Use the API to get the real image size
    var bounds = this.getBounds();
    boundx = bounds[0];
    boundy = bounds[1];
    
    console.log(1111);
    console.log(bounds);
    
    
    // Store the API in the jcrop_api variable
    jcrop_api = this;
  });

  function updatePreview(c)
  {
    if (parseInt(c.w) > 0)
    {
    	
    	
    	console.log(c);
    	img_x = c.x;
    	img_y = c.y;
    	img_w = c.w;
    	img_h = c.h;
    
		
      var rx = 100 / c.w;
      var ry = 100 / c.h;

      $('#p_img_preview').css({
        width: Math.round(rx * boundx) + 'px',
        height: Math.round(ry * boundy) + 'px',
        marginLeft: '-' + Math.round(rx * c.x) + 'px',
        marginTop: '-' + Math.round(ry * c.y) + 'px'
      });
      

    }
  };
}


第二步:

用户拖拽完裁剪框,点击裁剪按钮之后,上传四个参数,分别是起始点的横纵坐标和裁剪区域的宽度高度,

此次过程只上传参数,并没有上传图片,后台根据参数对上一步已经缩放的图片再次进行裁剪和缩放。

js代码略去,后台Java核心代码如下:

	/**
	 * 
	 * imgFileCut:传入一个图片文件输入流,写入裁减后的图片到输出流
	 * 
	 * @author 刘各欢
	 * @param postFix
	 * @param in
	 * @param out
	 * @param x
	 * @param y
	 * @param width
	 * @param height
	 * @param showHeight
	 * @param showWidth
	 * @throws IOException
	 * @since  Ver 1.1
	 */
    public void imgFileCut(String postFix,InputStream in,FileOutputStream out,int x,int y,int width,int height) throws IOException{
        ImageInputStream iis = null;
        try {

            /*
             * 返回包含所有当前已注册 ImageReader 的 Iterator,这些 ImageReader 声称能够解码指定格式。
             * 参数:formatName - 包含非正式格式名称 .(例如 "jpeg" 或 "tiff")等 。
             */
            Iterator<ImageReader> it = getImageReadersByFormatName(postFix);

            ImageReader reader = it.next();
            // 获取图片流
            iis = ImageIO.createImageInputStream(in);

            /*
             * <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);
            
            
            
            /* 
             * 缩放图片 
             */  
            Image imageSmall = bi.getScaledInstance(100, 100, Image.SCALE_DEFAULT);    
              
            BufferedImage small = new BufferedImage(100, 100, BufferedImage.TYPE_INT_RGB);  
              
            Graphics g = small.getGraphics();  
            g.drawImage(imageSmall, 0, 0, null); // 绘制缩小后的图  将Image绘制到BufferedImage中  
            g.dispose();  
            
            
            
            // 保存新图片
            ImageIO.write(small, postFix, out);
        } finally {
            if (in != null)
                in.close();
            if (iis != null)
                iis.close();
            if (out != null)
                out.close();
        }
    }
    
	public String saveTx(String zoomedImageName, String img_x, String img_y,
			String img_w, String img_h) {
		String zoomedImagePath = CommonInfo.touxiangPath+"/zoom/"+zoomedImageName;
		String finalImagePath = CommonInfo.touxiangPath+zoomedImageName;
		File zoomedImagefile = new File(zoomedImagePath);
		try {
			InputStream in = new FileInputStream(zoomedImagefile);
			File finalImage = new File(finalImagePath);
			FileOutputStream out = new FileOutputStream(finalImage);
			int x = new BigDecimal(img_x).intValue();
			int y = new BigDecimal(img_y).intValue();
			int w = new BigDecimal(img_w).intValue();
			int h = new BigDecimal(img_h).intValue();
			String postFix=zoomedImageName.substring(zoomedImageName.lastIndexOf(".")+1,zoomedImageName.length()).toLowerCase();
			this.imgFileCut(postFix, in, out, x, y, w, h);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			System.out.println("保存头像失败");
			return "error";
		}
		return "success";
	}







Control中的主调用方法:

	/**
	 * 
	 * updateZoomTx:对上传的原始头像进行等比例缩放,并返回文件名等一些参数
	 * 
	 * @author 刘各欢
	 * @param pic
	 * @param req
	 * @return
	 * @since  Ver 1.1
	 */
	@ResponseBody
	@RequestMapping(value = "/uploadZoomTx.do")
	public Map<String,Object> updateZoomTx(MultipartFile pic,HttpServletRequest req){
		Map<String,Object> map = null;
		if(req.getSession()!=null&&req.getSession().getAttribute("curruser")!=null){
			String uid = "";
			uid = ((User)(req.getSession().getAttribute("curruser"))).getId();
			map =userService.uploadZoomTx(pic,uid,req);
		}else{
			map=new HashMap<String,Object>();
			map.put("error","error");
		}
		return map;
	}
	
	/**
	 * 
	 * saveTx: 对上一步缩放过的图像进行裁剪并缩放,存在本地硬盘
	 * 
	 * @author 刘各欢
	 * @param zoomedImageName
	 * @param img_x
	 * @param img_y
	 * @param img_w
	 * @param img_h
	 * @param req
	 * @return
	 * @since  Ver 1.1
	 */
	@ResponseBody
	@RequestMapping(value = "/saveTx.do")
	public String saveTx(String zoomedImageName,String img_x,String img_y,String img_w,String img_h,HttpServletRequest req){
		String re =userService.saveTx( zoomedImageName,img_x, img_y, img_w, img_h);
		if(req.getSession()!=null&&req.getSession().getAttribute("curruser")!=null){
			User user = (User)(req.getSession().getAttribute("curruser"));
			user.setImage(zoomedImageName);
			userService.saveOrUpdate(user);
			return "ok";
		}else{
			return "error";
		}
	}



关于利用HTML5的canvas或者flash进行截取的也想过,考虑到兼容性,还是先这样吧。

相关资源:http://download.csdn.net/detail/lgh06/8343359 免积分

预览效果:

技术分享

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。