UNPKG

bsl

Version:

基于React的框架和UI组件

131 lines (119 loc) 4.82 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 | Blob, scaleWidth: 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; //获取图像的方位信息 EXIF.getData(file as any, function() { const orientation = parseInt(EXIF.getTag(file, 'Orientation')); const ratio = upImgHeight / upImgWidth; const scaleHeight = scaleWidth * ratio; const afterWidth = scaleWidth < upImgWidth ? scaleWidth : upImgWidth; const afterHeight = scaleWidth < upImgWidth ? scaleHeight : upImgHeight; let isRotate = false; if (upImgWidth < 10 || upImgWidth < 10) { alert('请不要上传过小的图片'); resolve(undefined); return; } else if (hidCtx) { // 设置压缩canvas区域高度及宽度 hidCanvas.setAttribute('width', afterWidth + 'px'); hidCanvas.setAttribute('height', afterHeight + 'px'); if (orientation <= 4) { if (orientation === 3 || orientation === 4) { isRotate = true; hidCtx.translate(scaleWidth, scaleHeight); hidCtx.rotate(180 * Math.PI / 180); } } else { if (orientation === 5 || orientation === 6) { isRotate = true; hidCtx.translate(scaleHeight, 0); hidCtx.rotate(90 * Math.PI / 180); } else if (orientation === 7 || orientation === 8) { isRotate = true; hidCtx.translate(0, scaleWidth); 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) { const useBlob = isRotate || afterWidth !== upImgWidth; resolve([result, useBlob ? blob : file]); } }, '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;