简单介绍
GraphicsMagick是ImageMagick的一个分支,相对于ImageMagick而言,TA处理速度更快,消耗资源更少。GraphicsMagick 是一个用来读写、生成超过90种图像格式的工具集合,支持包括 TIFF, JPEG, JPEG-2000,PNG, PDF, PhotoCD, SVG, 和GIF 等图像格式。GraphicsMagick 是基于 ImageMagick 开发的。
im4java是ImageMagick的另一个Java开源接口。与JMagick不同之处在于im4java只是生成与ImageMagick相对应的命令行,然后将生成的命令行传至选中的IM-command(使用java.lang.ProcessBuilder.start()实现)来执行相应的操作。它支持大部分ImageMagick命令,可以针对不同组的图片多次复用同一个命令行。im4java也是能够高清压缩图片,而且它也特别强大,至少一些基本常见的业务都是可以完美实现的。
Cropper是一款使用简单且功能强大的图片剪裁jQuery插件。该图片剪裁插件支持图片放大缩小,支持鼠标滚轮操作,支持图片旋转,支持触摸屏设备,支持canvas,并且支持跨浏览器使用。
技术选型
ImageCropper + GraphicsMagick + im4java + SpringMVC
ImageCropper官网: http://fengyuanchen.github.io/cropper/
GraphicsMagick官网: http://www.graphicsmagick.org/
im4java下载: http://sourceforge.net/projects/im4java/files/?source=navbar
处理逻辑
1、前端进行图片剪裁,并展示剪裁后的效果图;
2、点击确定后,将参数(x,y坐标,长宽,旋转角度)传到后端,并将图片上传至服务器,在调用im4java api进行图片处理。
3、返回处理后的图片路径,前端展示。
编程实现
图片剪裁处理类
package org.hcm.utils; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.im4java.core.ConvertCmd; import org.im4java.core.IM4JavaException; import org.im4java.core.IMOperation; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; public class ImageUtils { private static Log logger = LogFactory.getLog(ImageUtils.class); /** * 保存文件 * * @param inputStream * @param path * @param fileName */ public static void saveFileFromInputStream(InputStream inputStream, String path, String fileName) { File file = new File(path + fileName); FileOutputStream fs = null; try { fs = new FileOutputStream(file); byte[] buffer = new byte[1024 * 1024]; int byteread = 0; while ((byteread = inputStream.read(buffer)) != -1) { fs.write(buffer, 0, byteread); fs.flush(); } } catch (FileNotFoundException e) { logger.error("File Not Found !", e); } catch (IOException e) { logger.error("", e); } finally { try { if (fs != null) { fs.close(); } if (inputStream != null) { inputStream.close(); } } catch (IOException e) { logger.error("", e); } } } /** * 裁剪图片 * * @param imagePath * 源图片路径 * @param newPath * 处理后图片路径 * @param x * 起始X坐标 * @param y * 起始Y坐标 * @param width * 裁剪宽度 * @param height * 裁剪高度 * @return 返回true说明裁剪成功,否则失败 */ public static boolean cutImage(String imagePath, String newPath, int x, int y, int width, int height) { boolean flag = false; try { IMOperation op = new IMOperation(); op.addImage(imagePath); /** width:裁剪的宽度 * height:裁剪的高度 * x:裁剪的横坐标 * y:裁剪纵坐标 */ op.crop(width, height, x, y); op.addImage(newPath); ConvertCmd convert = new ConvertCmd(true); convert.run(op); flag = true; } catch (IOException e) { logger.error("读取文件出错", e); } catch (InterruptedException e) { logger.error("", e); } catch (IM4JavaException e) { logger.error("", e); } return flag; } /** * 根据尺寸缩放图片[等比例缩放:参数height为null,按宽度缩放比例缩放;参数width为null,按高度缩放比例缩放] * * @param imagePath * 源图片路径 * @param newPath * 处理后图片路径 * @param width * 缩放后的图片宽度 * @param height * 缩放后的图片高度 * @return 返回true说明缩放成功,否则失败 */ public static boolean zoomImage(String imagePath, String newPath, Integer width, Integer height) { boolean flag = false; try { IMOperation op = new IMOperation(); op.addImage(imagePath); if (width == null) { // 根据高度缩放图片 op.resize(null, height); } else if (height == null) { // 根据宽度缩放图片 op.resize(width); } else { op.resize(width, height); } op.addImage(newPath); ConvertCmd convert = new ConvertCmd(true); convert.run(op); flag = true; } catch (IOException e) { logger.error("读取文件出错", e); } catch (InterruptedException e) { logger.error("", e); } catch (IM4JavaException e) { logger.error("", e); } return flag; } /** * 图片旋转 * * @param imagePath * 源图片路径 * @param newPath * 处理后图片路径 * @param degree * 旋转角度 */ public static boolean rotate(String imagePath, String newPath, double degree) { boolean flag = false; try { // 1.将角度转换到0-360度之间 degree = degree % 360; if (degree <= 0) { degree = 360 + degree; } IMOperation op = new IMOperation(); op.addImage(imagePath); op.rotate(degree); op.addImage(newPath); ConvertCmd cmd = new ConvertCmd(true); cmd.run(op); flag = true; } catch (Exception e) { logger.error("图片旋转处理失败!", e); } return flag; } public static boolean imgProcessing(String srcPath, String destPath, int x, int y, int width, int height, double rotate) { boolean flag = false; try { IMOperation op = new IMOperation(); op.addImage(srcPath); /** 旋转 */ op.rotate(rotate); /** width:裁剪的宽度 * height:裁剪的高度 * x:裁剪的横坐标 * y:裁剪纵坐标 */ op.crop(width, height, x, y); op.addImage(destPath); ConvertCmd convert = new ConvertCmd(true); convert.run(op); flag = true; } catch (IOException e) { logger.error("读取文件出错", e); } catch (InterruptedException e) { logger.error("", e); } catch (IM4JavaException e) { logger.error("", e); } return flag; } public static void main(String[] args) { // ImageUtils.zoomImage("f://temp//test.jpg", "f://temp//test5.jpg", 200, 200); // ImageUtils.rotate("f://temp//test1.jpg", "f://temp//test2.jpg", -90); // ImageUtils.cutImage("f://temp//test5.jpg", "f://temp//test5.jpg", 32, 30, 200, 200); String data = "{'x':100.001, 'y':100.9}"; System.out.println(data); JSONObject jsonData = JSON.parseObject(data); System.out.println(jsonData.getIntValue("x")); System.out.println(jsonData.getIntValue("y")); } }
控制类
package org.hcm.controller; import java.io.IOException; import java.util.HashMap; import java.util.Map; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.lang.StringUtils; import org.hcm.utils.ImageUtils; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartHttpServletRequest; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; @Controller @RequestMapping(value = "/image") public class ImageController { @RequestMapping(value = "/upload", method = RequestMethod.POST) public void upload(HttpServletRequest req, HttpServletResponse resp) throws IOException { Map<String, Object> result = new HashMap<String, Object>(); MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) req; MultipartFile file = multipartRequest.getFile("avatar_file"); String data = req.getParameter("avatar_data"); String fileName = String.valueOf(System.currentTimeMillis()) + getExtension(file.getOriginalFilename()); String savePath = req.getServletContext().getRealPath("/upload"); if (!file.isEmpty()) { // 保存原图 ImageUtils.saveFileFromInputStream(file.getInputStream(), savePath + "\\source\\", fileName); // 处理图片 result = imageProcessing(data, savePath, fileName, req.getContextPath()); } resp.getWriter().print(JSON.toJSON(result)); } private Map<String, Object> imageProcessing(String data, String savePath, String fileName, String contextPath) { Map<String, Object> map = new HashMap<String, Object>(); JSONObject object = JSONObject.parseObject(data); int x = (int) object.getIntValue("x"); int y = object.getIntValue("y"); int height = object.getIntValue("height"); int width = object.getIntValue("width"); int rotate = object.getIntValue("rotate"); String srcPath = savePath + "\\source\\" + fileName; String destPath = savePath + "\\procesed\\" + fileName; String serverPath = contextPath + "/upload/procesed/" + fileName; ImageUtils.imgProcessing(srcPath, destPath, x, y, width, height, rotate); map.put("state", 200); map.put("result", serverPath); return map; } private String getExtension(String fileName) { if (StringUtils.INDEX_NOT_FOUND == StringUtils.indexOf(fileName, ".")) return StringUtils.EMPTY; String ext = StringUtils.substring(fileName, StringUtils.lastIndexOf(fileName, ".")); return StringUtils.trimToEmpty(ext); } }
效果预览
(完)