UNPKG

bsl

Version:

基于React的框架和UI组件

133 lines (119 loc) 4.94 kB
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;