# 业务背景
突然有一次搞活动,需要用户上传自己的自拍照,然后服务器端把头像做些特殊处理,这个时候可能会遇到的坑。
## 坑点二:人像是倒着的
如果用户直接采用摄像头拍照,这样的话获取到的照片可能会是倒着的,这样是影响业务的。
## 坑点一:图片过大
现在手机拍出来的照片,基本都是5M 以上的图片,对于上传压力太大了。
# 解决方案
## 人像是倒着的: exif.js 来解决
可以通过 exif.js 来获取图片的各种信息。
采用的是 [exif-js](https://www.npmjs.com/package/exif-js) 来获取图片基本信息
函数封装:
```js
const getImgExif = function (file, callback) {
$('#hideImg').attr('src', ''); // 先清空操作
var reader = new FileReader();
// 文件base64化,以便获知图片原始尺寸
reader.onload = function (e) {
var imgBase64 = e.target.result;
$('#hideImg').attr('src', imgBase64);
var $img = document.getElementById('hideImg');
$img.onload = function () {
window.EXIF.getData($img, function () {
var orientation = EXIF.getTag(this, 'Orientation');
callback(false, orientation, imgBase64);
});
};
};
reader.readAsDataURL(file);
}
```
这样就可以获取到图片的`orientation` 属性了。
## 图片过大:canvas 压缩图片
可以利用 `canvas` 提供的 `drawImage` 方法来实现 图片的压缩。
核心方法
```js
/**
*
* @param imgBase64 图片的 base64
* @param rotate 旋转角度
* @param maxW 压缩的最大宽度
* @param maxH 压缩的最大高度
* @param callback 回调函数。
*/
function rotateImg(imgBase64, rotate, maxW, maxH, callback) {
var img = new Image();
img.src = imgBase64;
if (typeof maxW == 'function') {
callback = maxW;
maxW = null;
maxH = null;
}
if (rotate) {
if (rotate !== '90' && rotate !== '-90' && rotate !== '180') {
rotate = null;
}
}
img.onload = function (ev) {
var originWidth = this.width;
var originHeight = this.height;
var targetWidth = originWidth;
var targetHeight = originHeight;
var maxWidth = maxW || 750, maxHeight = maxH || 750;
if (originWidth > maxWidth || originHeight > maxHeight) {
if (originWidth / originHeight > maxWidth / maxHeight) {
targetWidth = maxWidth;
targetHeight = Math.round(maxWidth * (originHeight / originWidth));
} else {
targetHeight = maxHeight;
targetWidth = Math.round(maxHeight * (originWidth / originHeight));
}
}
var canvas = document.createElement('canvas');
var context = canvas.getContext('2d');
canvas.width = targetWidth;
canvas.height = targetHeight;
context.clearRect(0, 0, targetWidth, targetHeight);
context.drawImage(img, 0, 0, originWidth, originHeight, 0, 0, targetWidth, targetHeight);
var dataUrl = canvas.toDataURL("image/jpeg");
if (rotate) {
var angle = 0;
var canvas2 = document.createElement('canvas');
var context2 = canvas2.getContext('2d');
canvas2.width = targetWidth;
canvas2.height = targetHeight;
var _setting = {
dx: 0,
dy: 0,
dw: 0,
dh: 0,
transX: 0,
transY: 0
};
var scale = 0;
if (rotate === '180') {
angle = Math.PI;
_setting.dw = targetWidth;
_setting.dh = targetHeight;
context2.translate(targetWidth, targetHeight);
context2.rotate(angle);
context2.translate(0, 0);
}
else {
if (rotate === '90') {
angle = 90 * (Math.PI / 180);
}
else if (rotate === '-90') {
angle = -90 * (Math.PI / 180);
}
_setting.transX = parseFloat(targetHeight / 2);
_setting.transY = parseFloat(targetWidth / 2);
_setting.dw = targetHeight;
scale = targetWidth / targetHeight;
_setting.dh = parseFloat(_setting.dw / scale);
_setting.dy = (targetWidth - _setting.dh) / 2;
context2.translate(_setting.transX, _setting.transY);
context2.rotate(angle);
context2.scale(scale, scale);
}
/**
* ctx.drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight);
*
* image: 可以是一个image ,或者一个canvas
* sx: 在画布所绘制图片本身的x轴的距离
* sy: 在画布所绘制图片本身y轴的距离
* sWidth:表示所绘制图片的宽度范围,一般默认是图片的完整大小。也可以是部分绘制。
* sHeight:表示所绘制图片的高度范围,一般默认是图片的完整大小。也可以是部分绘制。
* dx:表示在画布x轴的坐标值
* dy:表示在画布y轴的坐标值
* dWidth: 在画布绘制的宽度
* dHeight:在画布绘制的长度
*/
context2.drawImage(canvas, 0, 0, targetWidth, targetHeight, _setting.dx - _setting.transX, _setting.dy - _setting.transY, _setting.dw, _setting.dh);
dataUrl = canvas2.toDataURL("image/jpeg");
}
callback(dataUrl);
};
}
```
# demo
demo地址:https://bosscheng.github.io/canvas-rotate-image
demo2地址:https://bosscheng.github.io/web-h5/2018%E4%B8%96%E7%95%8C%E6%9D%AF/wap0618/index.html
github地址:https://github.com/bosscheng/canvas-rotate-image