bsl
Version:
基于React的框架和UI组件
133 lines (119 loc) • 4.94 kB
text/typescript
import * as EXIF from 'exif-js';
/**
* 以下代码是修复canvas在ios中显示压缩的问题。
* Detecting vertical squash in loaded image.
* Fixes a bug which squash image vertically while drawing into canvas for some images.
* This is a bug in iOS6 devices. This function from https://github.com/stomita/ios-imagefile-megapixel
*
*/
function detectVerticalSquash(img: HTMLImageElement) {
// const iw = img.naturalWidth;
const ih = img.naturalHeight;
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d')!;
const data = ctx.getImageData(0, 0, 1, ih).data;
let sy = 0;
let ey = ih;
let py = ih;
canvas.width = 1;
canvas.height = ih;
ctx.drawImage(img, 0, 0);
// search image edge pixel position in case it is squashed vertically.
while (py > sy) {
const alpha = data[(py - 1) * 4 + 3];
if (alpha === 0) {
ey = py;
} else {
sy = py;
}
py = (ey + sy) >> 1;
}
const ratio = (py / ih);
return ratio === 0 ? 1 : ratio;
}
/**
* A replacement for context.drawImage
* (args are for source and destination).
*/
// tslint:disable-next-line: max-line-length
function drawImageIOSFix(ctx: CanvasRenderingContext2D, img: HTMLImageElement, sx: number, sy: number, sw: number, sh: number, dx: number, dy: number, dw: number, dh: number) {
const vertSquashRatio = detectVerticalSquash(img);
// Works only if whole image is displayed:
// ctx.drawImage(img, sx, sy, sw, sh, dx, dy, dw, dh / vertSquashRatio);
// The following works correct also when only a part of the image is displayed:
ctx.drawImage(img, sx * vertSquashRatio, sy * vertSquashRatio, sw * vertSquashRatio, sh * vertSquashRatio, dx, dy, dw, dh);
}
function compressImg(file: File, afterWidth: number): Promise<[string, Blob] | undefined> {
return new Promise((resolve, reject) => {
const hidCanvas = document.createElement('canvas');
let hidCtx: CanvasRenderingContext2D | null = null;
let result = '';
//生成隐藏画布
if (hidCanvas.getContext) {
hidCtx = hidCanvas.getContext('2d');
} else {
alert('对不起,您的浏览器不支持图片压缩及上传功能,请换个浏览器试试~');
return;
}
const reader = new FileReader();
const image = new Image();
reader.readAsDataURL(file);
image.onload = () => {
const upImgWidth = image.width;
const upImgHeight = image.height;
let orientation = 1;
//获取图像的方位信息
EXIF.getData(image.src, () => {
orientation = parseInt(EXIF.getTag(image.src, 'Orientation'));
orientation = orientation ? orientation : 1;
});
// 只对图片做放小图片,如果图片本来比屏幕尺寸小就使用本身的尺寸
const width = afterWidth < upImgWidth ? afterWidth : upImgWidth;
//压缩换算后的图片高度
const afterHeight = width * upImgHeight / upImgWidth;
if (upImgWidth < 10 || upImgWidth < 10) {
alert('请不要上传过小的图片');
resolve(undefined);
return;
} else if (hidCtx) {
if (orientation <= 4) {
// 设置压缩canvas区域高度及宽度
hidCanvas.setAttribute('height', afterHeight + 'px');
hidCanvas.setAttribute('width', afterWidth + 'px');
if (orientation === 3 || orientation === 4) {
hidCtx.translate(afterWidth, afterHeight);
hidCtx.rotate(180 * Math.PI / 180);
}
} else {
// 设置压缩canvas区域高度及宽度
hidCanvas.setAttribute('height', afterHeight + 'px');
hidCanvas.setAttribute('width', afterWidth + 'px');
if (orientation === 5 || orientation === 6) {
hidCtx.translate(afterHeight, 0);
hidCtx.rotate(90 * Math.PI / 180);
} else if (orientation === 7 || orientation === 8) {
hidCtx.translate(0, afterWidth);
hidCtx.rotate(270 * Math.PI / 180);
}
}
// canvas绘制压缩后图片
drawImageIOSFix(hidCtx, image, 0, 0, upImgWidth, upImgHeight, 0, 0 , afterWidth, afterHeight);
// 获取压缩后生成的img对象
result = hidCanvas.toDataURL('image/jpeg');
// 获取压缩后生成的blob对象
hidCanvas.toBlob((blob) => {
if (blob) {
resolve([result, blob]);
}
}, 'image/jpeg', 1);
}
};
reader.onload = (evt) => {
const target = evt.target as FileReader;
const srcString = target.result as string;
//安卓获取的base64数据无信息头,加之
image.src = srcString.substring(5, 10) !== 'image' ? srcString.replace(/(.{5})/, '$1image/jpeg;') : srcString;
};
});
}
export default compressImg;