共计 2971 个字符,预计需要花费 8 分钟才能阅读完成。
有时候咱们有这样的需要,就是对前端选中的图片进行压缩解决。
这样解决的起因可能是。
- 缩小带宽占用率,提高效率。
- 对图片进行裁剪合乎上传需要。(当初手机拍照分辨率很高,间接拿来用比拟大。)
前端对图片进行压缩次要应用到的 API 有:
- Canvas
- Image
- File
- Blob
- FileReader
如图,设置三个办法
- toImage
- toCanvas
- toFile
/** 次要办法 */ | |
async function miniImage(params:{ | |
url?:string, | |
file?:File, | |
quality?:number, | |
fileName?:string, | |
size?:{width:number,height:number}, | |
fitLength?:number | |
}={quality:1,fileName:'压缩图片'} | |
){console.assert(params.url||params.file,'url 和 file 必填其一') | |
console.assert(params.quality<=1&¶ms.quality>0,'quality 的取值范畴是 0 -1') | |
const img = await toImage({file:params.file,url:params.url}) | |
const canvas = toCanvas({img,size:params.size,fitLength:params.fitLength}) | |
return await toFile(canvas,{quality:params.quality,fileName:params.fileName}) | |
} |
toImage 办法
该办法次要是应用 Image 以及 File、FileReader 来进行转换,传参如果是 file,则应用后者,如果只是 url,则间接应用 Image。
其中留神 FilerReader 的用法,在 h5 的开发中很多中央都会应用到。
/** 转换成图片 */ | |
async function toImage (params: {file?: File, url?: string}): Promise<HTMLImageElement> {return new Promise((reso, rej) => {const {file, url} = params | |
const img = new Image() | |
img.onload = () => {return reso(img) | |
} | |
// 文件形式 | |
if (file) {const reader = new FileReader() | |
reader.onload = (e) => {img.setAttribute('src', e.target?.result as string) | |
} | |
reader.readAsDataURL(file) | |
} else if (url) {img.setAttribute('src', url) | |
} else {console.error(` 解析图片出错 `) | |
} | |
}) | |
} |
toCanvas 办法
该办法次要是应用 CanvasRenderingContext2D 的 drawImage 办法。
该办法的入参定义:drawImage(HTMLImageElement,dx,dy,dw,dh)
即传入办法,而后绘制图片,管制绘制地位,以及绘制的宽高。
此外咱们还须要做更多的兼容,减少入参,管制图片的尺寸。代码如下。
/** 转换成 canvas */ | |
function toCanvas (img: HTMLImageElement, options?: {size?: {width: number, height: number}, maxLength?: number}) {const canvas = document.createElement('canvas') | |
let {size, maxLength} = options ?? {} | |
let {height, width} = img | |
if (size || maxLength) {if ((!size?.height || !size.width) && !maxLength) maxLength = size?.height ?? size?.width | |
// 设置长度并去适应 | |
if (maxLength) {let maxlen = Math.max(height, width) | |
let rate = maxLength / maxlen | |
height = maxlen === height ? maxLength : height * rate | |
width = maxlen === width ? maxLength : width * rate | |
} else if (size) { | |
// 设置了尺寸 | |
height = size.height | |
width = size.width | |
} | |
} | |
canvas.height = height | |
canvas.width = width | |
const ctv = canvas.getContext('2d') | |
ctv?.drawImage(img, 0, 0, width, height) | |
return canvas | |
} |
toFile 办法
最初一步,把图片转成咱们须要的文件用以上传。
该步骤次要是应用 canvas 的 toBlob 办法,而后通过 File 来生成新的 file。
注:在 js 中,一个文件根本就是 Blob 加上 name。
具体代码如下:
/**canvas 转文件 */ | |
function canvasToFile (canvas: HTMLCanvasElement, options: {fileName?: string, quality?: number} = {quality: 1, fileName: '图片'}): Promise<File> {return new Promise((reso, rej) => {canvas.toBlob((blob) => {const file = new File([ blob as Blob], options!.fileName as string, {type: 'image/png',}) | |
reso(file) | |
}, '', options.quality) | |
}) | |
} |
miniImageByUrl 办法
最初咱们联合下面在写一个办法用来预览,把生成的 canvas 间接转成 dataUrl,在页面展现。
/** 解决图片压缩,并且转成 url */ | |
export const imageMinByUrl = async ( | |
params: { | |
file?: File | |
url?: string | |
quality?: number | |
maxLength?: number, | |
size?: {height: number, width: number}, | |
} = {quality: 1} | |
) => {console.assert(params.file || params.url, '必须存在 file 或者 url 入参') | |
const img = await toImage({file: params.file, url: params.url}) | |
const canvas = toCanvas(img, {size: params.size, maxLength: params.maxLength}) | |
return canvas.toDataURL('image/png', params.quality) | |
} |
npm 中能够通过 cdd-lib 间接应用,该库提供了 imageMinByUrl
和imageMin
办法。
参考:
- <<How to resize image in Javascript?>>
正文完