您的位置:首页 > Web前端 > AngularJS

js,angularjs 图片上传服务器,并解决照片旋转问题,前端图片压缩上传

2017-07-29 11:33 926 查看
手机网站 App 开发时遇到用户拍照上传的场景,照片的大小一般不低于2M ,用户网络不好时会导致上传的时候异常卡顿,因此考虑使用前端图片压缩,再上传服务器.

主要使用canvas来重新绘制前端图片,然后使用toDataURL方法拿到图片被压缩之后的的 Base64 编码数据,上传编码数据,后台解码还原成图片,并根据前端传递的图片旋转信息将图片做相应的旋转处理,废话不多说,直接上代码,虽然说的是 angularjs 的压缩图片上传,其实跟 angularjs 基本没有关系纯粹的 js 代码实现的图片重绘:

前端主要代码

this.uploadPic = function(file, success, fail) {
if (!/image\/\w+/.test(file.type)) {
alert("image only please.");
return false;
}
//EXIF为一个 js 读取图片参数工具类,可以用来读取照片被旋转的角度,
//用作后端代码修正照片旋转,
EXIF.getData(file,function() {
//orient即读取到的照片旋转参数
orient = EXIF.getTag(this,'Orientation');
var rotate = 0;
if (orient != null && orient != ""&& orient != 1) {
switch (orient) {
case 6:// 需要顺时针(向左)90度旋转
rotate = 90;
break;
case 8:// 需要逆时针(向右)90度旋转
rotate = 270;
break;
case 3:// 需要180度旋转
rotate = 180;
break;
}
}
//此处开始读取图片并使用canvas将读取到的信息重新绘制
var reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = function(e) {
var img = new Image, width = 640, // image
// resize
quality = 0.8, // image
// quality
canvas = document.createElement("canvas"),
drawer = canvas.getContext("2d");
img.src = this.result;
img.onload = function() {
canvas.width = width;
canvas.height = width * (img.height / img.width);
//开始绘制图片(压缩之后)
drawer.drawImage(img, 0, 0,canvas.width,canvas.height);
//获取压缩之后的 base64 编码的数据
bodyData = canvas.toDataURL("image/jpeg",quality);
//上传图片的 base64 编码信息
$http.post("/common/upload-base64?rotate="
+ rotate,bodyData)
.success(function(data) {
success(data);
})
.error(function(data) {
fail(data);
});
}
}
});
}


在需要上传图片的地方调用uploadPic方法即可,file 传入 input.files[0] success 为上传成功之后的回调方法,fail 为上传失败之后的回调;

后端代码:

@RequestMapping(value = "/upload-base64", method = RequestMethod.POST)
@ResponseBody
public Map<String, Object> uploadFileBase64(HttpServletRequest request,
HttpServletResponse response,@RequestBody String fileBase64,
@RequestParam(required = false, value = "rotate", defaultValue = "0")
int rotate) throws IOException {
logger.info("开始上传base64格式的文件:");
long begin = System.currentTimeMillis();
//前端上传的数据的开始部分为文件标识信息,在解码之前需要去掉这部分信息
fileBase64 = fileBase64.replace("data:image/jpeg;base64,", "");
// Base64解码
byte[] bytes = Base64.decodeBase64(fileBase64);
for (int i = 0; i < bytes.length; ++i) {
if (bytes[i] < 0) {// 调整异常数据
bytes[i] += 256;
}
}
String separator = "/";
String realServerPath = request.getSession().getServletContext()
.getRealPath(separator);
Date date = new Date();
String dateStr = new SimpleDateFormat("yyyyMMdd").format(date);
String timeStr = new SimpleDateFormat("HHmmssSSS").format(date);
// 存储的相对路径, 用于返回到页面
StringBuffer relativePath = new StringBuffer();
relativePath.append(this.uploadPath).append(separator).append(dateStr);
StringBuffer uploadDir = new StringBuffer();
uploadDir.append(realServerPath).append(separator).append(relativePath);
File dirPath = new File(uploadDir.toString());
if (!dirPath.exists()) {
dirPath.mkdirs();
}
StringBuffer savedFileName = new StringBuffer();
savedFileName.append(dateStr).append(timeStr)
.append(new Random().nextInt()).append(".").append("jpg");
String realFilePath = uploadDir + separator + savedFileName;
File uploadedFile = new File(realFilePath);
//写入图片
FileCopyUtils.copy(bytes, uploadedFile);
logger.info("上传base64文件成功:" + ",耗时:"
+ (System.currentTimeMillis() - begin) + "ms");
//校验是否需要对图片做旋转处理
if (ImageUtil.ANGLE_0 != rotate) {
ImageUtil.rotatePhonePhoto(realFilePath, rotate);
}

Map<String, Object> map = new HashMap<>();
map.put("relativePath", relativePath + separator + savedFileName);
return map;
}


旋转图片的代码如下:

/**
* 将图片旋转一定角度
*
* @param fullPath
* @param angel
* @return
*/
public static String rotatePhonePhoto(String fullPath, int angel) {
logger.info("旋转图片:" + fullPath + " 角度:" + angel);
long begin = System.currentTimeMillis();
BufferedImage src;
try {
ImageIO.setUseCache(false);
src = ImageIO.read(new File(fullPath));
int src_width = src.getWidth(null);
int src_height = src.getHeight(null);
Rectangle rect_des = calcRotatedSize(new Rectangle(
new Dimension(src_width, src_height)), angel);

BufferedImage res = new BufferedImage(rect_des.width,
rect_des.height, BufferedImage.TYPE_INT_RGB);
Graphics2D g2 = res.createGraphics();

g2.translate((rect_des.width - src_width) / 2,
(rect_des.height - src_height) / 2);
g2.rotate(Math.toRadians(angel), src_width / 2,
src_height / 2);

g2.drawImage(src, null, null);
//注意此处使用 jpg 格式,如果使用其他格式编码会出现效率的诸多问题
ImageIO.write(res, "jpg", new File(fullPath));

} catch (IOException e) {
logger.error("", e);
}
logger.info("旋转图片:" + fullPath + " 角度:" + angel
+ "  耗时:" + (System.currentTimeMillis() - begin) + "ms");
return fullPath;

}

/**
* 计算新照片的大小
*
* @param src
* @param angel
* @return
*/
public static Rectangle calcRotatedSize(Rectangle src, int angel) {
// if angel is greater than 90 degree, we need to do some conversion
if (angel >= 90) {
if (((angel / 90) % 2) == 1) {
int temp = src.height;
src.height = src.width;
src.width = temp;
}
angel = angel % 90;
}

double r = Math.sqrt((src.height * src.height)
+ (src.width * src.width)) / 2;
double len = 2 * Math.sin(Math.toRadians(angel) / 2) * r;
double angel_alpha = (Math.PI - Math.toRadians(angel)) / 2;
double angel_dalta_width = Math.atan((double) src.height / src.width);
double angel_dalta_height = Math.atan((double) src.width / src.height);

int len_dalta_width = (int) (len * Math.cos(Math.PI
- angel_alpha - angel_dalta_width));
int len_dalta_height = (int) (len * Math.cos(Math.PI
- angel_alpha - angel_dalta_height));
int des_width = src.width + (len_dalta_width * 2);
int des_height = src.height + (len_dalta_height * 2);
return new Rectangle(new Dimension(des_width, des_height));
}


以上代码即可解决图片压缩上传,照片翻转的问题

如果想上传图片原图,并在后端做图片的选择操作,最好在后端直接读取图片,EXIF.js读取图片信息时非常慢,但由于图片重新绘制会丢失照片原有的旋转信息因此前端压缩时必须读取照片旋转角度以便后台修正,如果前端直接上传原图,可以在后台使用

<dependency>
<groupId>com.drewnoakes</groupId>
<artifactId>metadata-extractor</artifactId>
<version>2.10.1</version>
</dependency>


来读取照片信息,并获取需要旋转的角度

主要代码如下:

/**
* 获取图片的旋转角度
*
* @param filePath
* @return 图片旋转角度
*/
public static int getRotateAngleForPhoto(String filePath) {
File file = new File(filePath);
int angle = ANGLE_0;
Metadata metadata;
try {
metadata = JpegMetadataReader.readMetadata(file);
Directory directory = metadata
.getFirstDirectoryOfType(ExifIFD0Directory.class);
if ((null != directory) && directory.containsTag(
ExifIFD0Directory.TAG_ORIENTATION)) {
// Exif信息中方向
int orientation = directory.getInt(
ExifIFD0Directory.TAG_ORIENTATION);
// 原图片的方向信息
if (6 == orientation) {
// 6旋转90
angle = ANGLE_90;
} else if (3 == orientation) {
// 3旋转180
angle = ANGLE_180;
} else if (8 == orientation) {
// 8旋转90
angle = ANGLE_270;
}
}
} catch (JpegProcessingException e) {
logger.error("", e);
} catch (MetadataException e) {
logger.error("", e);
} catch (IOException e) {
logger.error("", e);
}
return angle;
}


不压缩直接上传的前端代码如下,参数的意义与之前压缩上传的一致

this.uploadPicNotCompress = function(file, success, fail) {
if (!/image\/\w+/.test(file.type)) {
alert("image only please.");
return false;
}
var formdata = new FormData(); // 初始化一个FormData实例
formdata.append('file', file); // file就是图片或者其他你要上传的formdata
$http.post("common/upload", formdata, {
transformRequest : angular.identity,
headers : {
'Content-Type' : undefined
}})
.success(function(data) {
success(data);
})
.error(function(data) {
fail(data);
});
}


exif.js下载链接:http://pan.baidu.com/s/1jItDFMI 密码:m98m
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐