# 業(yè)務(wù)背景
突然有一次搞活動(dòng),需要用戶上傳自己的自拍照,然后服務(wù)器端把頭像做些特殊處理,這個(gè)時(shí)候可能會(huì)遇到的坑。
## 坑點(diǎn)二:人像是倒著的
如果用戶直接采用攝像頭拍照,這樣的話獲取到的照片可能會(huì)是倒著的,這樣是影響業(yè)務(wù)的。
## 坑點(diǎn)一:圖片過(guò)大
現(xiàn)在手機(jī)拍出來(lái)的照片,基本都是5M 以上的圖片,對(duì)于上傳壓力太大了。
# 解決方案
## 人像是倒著的: exif.js 來(lái)解決
可以通過(guò) exif.js 來(lái)獲取圖片的各種信息。
采用的是 [exif-js](https://www.npmjs.com/package/exif-js) 來(lái)獲取圖片基本信息
函數(shù)封裝:
```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` 屬性了。
## 圖片過(guò)大:canvas 壓縮圖片
可以利用 `canvas` 提供的 `drawImage` 方法來(lái)實(shí)現(xiàn) 圖片的壓縮。
核心方法
```js
? ? /**
? ? *
? ? * @param imgBase64? 圖片的 base64
? ? * @param rotate 旋轉(zhuǎn)角度
? ? * @param maxW 壓縮的最大寬度
? ? * @param maxH 壓縮的最大高度
? ? * @param callback 回調(diào)函數(shù)。
? ? */
? ? 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: 可以是一個(gè)image ,或者一個(gè)canvas
? ? ? ? ? ? ? ? * sx: 在畫布所繪制圖片本身的x軸的距離
? ? ? ? ? ? ? ? * sy: 在畫布所繪制圖片本身y軸的距離
? ? ? ? ? ? ? ? * sWidth:表示所繪制圖片的寬度范圍,一般默認(rèn)是圖片的完整大小。也可以是部分繪制。
? ? ? ? ? ? ? ? * sHeight:表示所繪制圖片的高度范圍,一般默認(rèn)是圖片的完整大小。也可以是部分繪制。
? ? ? ? ? ? ? ? * dx:表示在畫布x軸的坐標(biāo)值
? ? ? ? ? ? ? ? * dy:表示在畫布y軸的坐標(biāo)值
? ? ? ? ? ? ? ? * dWidth: 在畫布繪制的寬度
? ? ? ? ? ? ? ? * dHeight:在畫布繪制的長(zhǎng)度
? ? ? ? ? ? ? ? */
? ? ? ? ? ? ? ? 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