js压缩图片到指定大小

lizuncong (lizuncong) · GitHubI am a strong believer in reverse engineering. lizuncong has 42 repositories available. Follow their code on GitHub.https://github.com/lizuncong

需求:前端上传图片的时候通常需要提供指定大小以内的图片。比如不大于500KB。

思路:利用canvas转blob的时候通过quality控制图片质量,达到压缩的目的。此方法有个缺点。只能对图片格式为jpeg或webp的图片有效。因此压缩的时候canvas.toBlob(callback, mimeType, quality)中的mimeType要设为'image/jpeg'。压缩完成可以自行转成想要的格式。这里最主要的是找到小于maxSize并且最接近maxSize的图片质量参数quality。

可以在这里在线玩一下哦

效果图:用进度条模拟压缩的进度。支持同时上传多张图片同时压缩

 代码如下:

import React from 'react';
import PropTypes from 'prop-types';
import styles from './upload.less';import compress from './compress';class Upload extends React.Component {constructor(props) {super(props);this.fileInput = React.createRef();this.state = {fileObjs: [], // item { originFile, compressBase64, compressFile }};}getFileUrl(file) {let url;const agent = navigator.userAgent;if (agent.indexOf('MSIE') >= 1) {url = file.value;} else if (agent.indexOf('Firefox') > 0 || agent.indexOf('Chrome') > 0) {url = window.URL.createObjectURL(file);}return url;}compressCallBack(file, fileObj, result) {const { fileObjs } = this.state;file.compressing = false; // 压缩完成fileObj.compressBase64 = result.compressBase64;fileObj.compressFile = result.compressFile;this.setState({ fileObjs: [...fileObjs] });if (fileObjs.length && fileObjs.every(fileObjItem => fileObjItem.compressBase64)) {console.log('全部压缩完成', fileObjs);}}onInputChange(e) {const { fileObjs } = this.state;Object.keys(e.target.files).forEach((key) => {const file = e.target.files[key];// 验证图片格式const type = file.name.split('.')[1];if (type !== 'png' && type !== 'jpg' && type !== 'jpeg') {console.warn('请上传png,jpg,jpeg格式的图片!');e.target.value = '';return;}file.url = this.getFileUrl(file);file.compressing = true; // 压缩状态,开始压缩const fileObj = { originFile: file, compressBase64: null, compressFile: null };fileObjs.push(fileObj);// 压缩图片的方法, maxSize单位为kbcompress(file, 200).then((res) => {this.compressCallBack(file, fileObj, res);}, (err) => {// 压缩失败,则返回原图片的信息this.compressCallBack(file, fileObj, err);});});this.setState({ fileObjs: [...fileObjs] });e.target.value = '';}render() {const { fileObjs } = this.state;return (<divclassName={styles.uploadContainer}><div className={styles.gridItem}><divclassName={styles.inputContainer}onClick={() => {this.fileInput.current.click();}}><span className={styles.uploadIcon}>+</span><inputclassName={styles.fileInput}ref={this.fileInput}type="file"name="file"multiple="multiple"accept="image/*"onChange={e => this.onInputChange(e)}/></div></div>{fileObjs.map(fileObj => (<div className={styles.gridItem}><imgsrc={fileObj.compressBase64 ? fileObj.compressBase64 : fileObj.originFile.url}className={fileObj.originFile.compressing && styles.filter}/>{fileObj.originFile.compressing ?<div className={styles.progressContainer}><div className={styles.progress}><div className={styles.progressHighlight} /></div></div> : ''}</div>))}</div>);}
}Upload.propTypes = {dispatch: PropTypes.func.isRequired,
};export default Upload;

2.图片压缩主要代码compress.js


// 将File(Blob)对象转变为一个dataURL字符串, 即base64格式
const fileToDataURL = file => new Promise((resolve) => {const reader = new FileReader();reader.onloadend = e => resolve(e.target.result);reader.readAsDataURL(file);
});// 将dataURL字符串转变为image对象,即base64转img对象
const dataURLToImage = dataURL => new Promise((resolve) => {const img = new Image();img.onload = () => resolve(img);img.src = dataURL;
});// 将一个canvas对象转变为一个File(Blob)对象
const canvastoFile = (canvas, type, quality) => new Promise(resolve => canvas.toBlob(blob => resolve(blob), type, quality));const compress = (originfile, maxSize) => new Promise(async (resolve, reject) => {const originSize = originfile.size / 1024; // 单位为kbconsole.log('图片指定最大尺寸为', maxSize, '原始尺寸为:', originSize);// 将原图片转换成base64const base64 = await fileToDataURL(originfile);// 缩放图片需要的canvasconst canvas = document.createElement('canvas');const context = canvas.getContext('2d');// 小于maxSize,则不需要压缩,直接返回if (originSize < maxSize) {resolve({ compressBase64: base64, compressFile: originfile });console.log(`图片小于指定大小:${maxSize}KB,不用压缩`);return;}const img = await dataURLToImage(base64);const scale = 1;const originWidth = img.width;const originHeight = img.height;const targetWidth = originWidth * scale;const targetHeight = originHeight * scale;canvas.width = targetWidth;canvas.height = targetHeight;context.clearRect(0, 0, targetWidth, targetHeight);context.drawImage(img, 0, 0, targetWidth, targetHeight);// 将Canvas对象转变为dataURL字符串,即压缩后图片的base64格式// const compressedBase64 = canvas.toDataURL('image/jpeg', 0.1);// 经过我的对比,通过scale控制图片的拉伸来压缩图片,能够压缩jpg,png等格式的图片// 通过canvastoFile方法传递quality来压缩图片,只能压缩jpeg类型的图片,png等格式不支持// scale的压缩效果没有canvastoFile好// 在压缩到指定大小时,通过scale压缩的图片比通过quality压缩的图片模糊的多// 压缩的思路,用二分法找最佳的压缩点// 这里为了规避浮点数计算的弊端,将quality转为整数再计算;// const preQuality = 100;const maxQualitySize = { quality: 100, size: Number.MAX_SAFE_INTEGER };const minQualitySize = { quality: 0, size: 0 };let quality = 100;let count = 0; // 压缩次数let compressFinish = false; // 压缩完成let invalidDesc = '';let compressBlob = null;// 二分法最多尝试8次即可覆盖全部可能while (!compressFinish && count < 12) {compressBlob = await canvastoFile(canvas, 'image/jpeg', quality / 100);const compressSize = compressBlob.size / 1024;count++;if (compressSize === maxSize) {console.log(`压缩完成,总共压缩了${count}次`);compressFinish = true;return;}if (compressSize > maxSize) {maxQualitySize.quality = quality;maxQualitySize.size = compressSize;}if (compressSize < maxSize) {minQualitySize.quality = quality;minQualitySize.size = compressSize;}console.log(`第${count}次压缩,压缩后大小${compressSize},quality参数:${quality}`);quality = Math.ceil((maxQualitySize.quality + minQualitySize.quality) / 2);if (maxQualitySize.quality - minQualitySize.quality < 2) {if (!minQualitySize.size && quality) {quality = minQualitySize.quality;} else if (!minQualitySize.size && !quality) {compressFinish = true;invalidDesc = '压缩失败,无法压缩到指定大小';console.log(`压缩完成,总共压缩了${count}次`);} else if (minQualitySize.size > maxSize) {compressFinish = true;invalidDesc = '压缩失败,无法压缩到指定大小';console.log(`压缩完成,总共压缩了${count}次`);} else {console.log(`压缩完成,总共压缩了${count}次`);compressFinish = true;quality = minQualitySize.quality;}}}if (invalidDesc) {// 压缩失败,则返回原始图片的信息console.log(`压缩失败,无法压缩到指定大小:${maxSize}KB`);reject({ msg: invalidDesc, compressBase64: base64, compressFile: originfile });return;}compressBlob = await canvastoFile(canvas, 'image/jpeg', quality / 100);const compressSize = compressBlob.size / 1024;console.log(`最后一次压缩(即第${count + 1}次),quality为:${quality},大小:${compressSize}`);const compressedBase64 = await fileToDataURL(compressBlob);const compressedFile = new File([compressBlob], originfile.name, { type: 'image/jpeg' });resolve({ compressFile: compressedFile, compressBase64: compressedBase64 });
});export default compress;

3.less

.uploadContainer{display: grid;grid-template-columns: repeat(auto-fill,minmax(75px, 1fr));grid-row-gap: .10rem;grid-column-gap: .08rem;.gridItem{position: relative;width: 100%;height: 0;padding-top: 100%;.inputContainer{position: absolute;left: 0;top: 0;width: 100%;height: 100%;display: flex;align-items: center;justify-content: center;border-radius:8px;border:1px solid rgba(217,217,217,1);.fileInput{display: none;}.uploadIcon{font-size: 30px;color: lightgrey;}}img{position: absolute;left: 0;top: 0;width: 100%;height: 100%;border-radius:8px;}.delete{position: absolute;top: -9px;right: -9px;width: 18px;height: 18px;background: red;color: white;border-radius: 50%;display: flex;align-items: center;justify-content: center;font-size: 20px;}.filter{filter: blur(1px);}.progressContainer{position: absolute;width: 80%;left: 50%;top: 50%;transform: translate(-50%, -50%);font-size: 10px;.progress{width: 100%;height: 4px;border-radius: 3px;border: 1px solid rgba(0,0,0,0.1);}.progressHighlight{height: 100%;width: 100%;animation: progress 3s cubic-bezier(0.25,0.1,0.25,1) infinite;background: orange;border-radius: 3px;}}}
}@keyframes progress
{0%   {width: 0}to  {width: 100%}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://xiahunao.cn/news/143826.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

前端JS实现图片质量压缩

前端JS实现图片质量压缩 用户在选择图片文件进行上传的时候是不会考虑文件的大小的&#xff0c;比如场景&#xff1a; 某用户只是想更换一下自己的用户头像&#xff0c;于是用自己的手机拍了一张照片&#xff0c;上传到应用中更换用户头像&#xff0c;然而现在的手机拍照功能…

掌握JS压缩图片,这一篇就够了

前言 公司的移动端业务需要在用户上传图片是由前端压缩图片大小&#xff0c;再上传到服务器&#xff0c;这样可以减少移动端上行流量&#xff0c;减少用户上传等待时长&#xff0c;优化用户体验。 插播一下&#xff0c;本文案例已整理成插件&#xff0c;已上传 npm &#xff…

实现图片前端JS压缩并上传

一、图片上传前端压缩的现实意义 对于大尺寸图片的上传&#xff0c;在前端进行压缩除了省流量外&#xff0c;最大的意义是极大的提高了用户体验。 这种体验包括两方面&#xff1a; 由于上传图片尺寸比较小&#xff0c;因此上传速度会比较快&#xff0c;交互会更加流畅&#…

js实现对上传图片进行压缩并且预览

js实现对上传图片的路径转成base64编码&#xff0c;并且对图片进行压缩&#xff0c;实现预览功能 需要先引入jquery: <script src"http://i.gtimg.cn/qzone/biz/gdt/lib/jquery/jquery-2.1.4.js?max_age31536000"></script> 1、html如下 <body>…

JS中通过指定大小来压缩图片

前不久王二写了一个图片处理库&#xff0c;可以指定图片质量压缩图片&#xff0c;调用的是javaScript的原生方法 toDataURL 和 toBlob&#xff0c;库里有如下这些方法&#xff1a; 但是通过质量压缩图片有一些不足之处&#xff1a;无法确定压缩后图片的大小&#xff1b; 比如下…

JavaScript前端实现压缩图片功能

JavaScript前端实现压缩图片功能 为什么要前端来压缩图片接下来看下详细步骤 为什么要前端来压缩图片 最近在做一个移动端h5上传图片的功能&#xff0c;本来这个功能并不复杂&#xff0c;只需要将图片文件通过axios传到服务端即可&#xff0c;但是考虑到现在手机设配的拍照功能…

HTML实现纯前端压缩图片

演示 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>压缩图片</title> </head> <bo…

前端js实现canvas压缩图片并上传

一. 上传前压缩图片的好处 可以减少用户的等待时间&#xff0c;提升使用体验&#xff0c;目前手机拍摄的图片文件大小一般在几 M 左右&#xff0c;文件直接上传时会有卡顿现象。可以减少服务端的存储空间。再次回去图片资源是也可以快速的加载。虽然目前阿里云的 oss 有相对应…

JS前端图片压缩上传-纯js

JS前端图片压缩上传-纯js 最近在做一个手机端的图片上传&#xff0c;写了一个比较符合自己要求的方法&#xff0c;可供参考 在做这个功能模块时&#xff0c;我遇到了以下问题&#xff0c;都花费了大量时间&#xff1a; 1. 不知道怎么压缩图片&#xff0c;&#xff08;代码和…

JS前端图片压缩上传

JS前端图片压缩上传重点知识 最近在做一个手机端的图片上传&#xff0c;写了一个比较符合自己要求的方法&#xff0c;可供参考 在做这个功能模块时&#xff0c;我遇到了以下问题&#xff0c;都花费了大量时间&#xff1a; 1. 不知道怎么压缩图片&#xff0c;&#xff08;代码…

图片纯前端JS压缩的实现

一、功能体验 先看demo&#xff1a;使用canvas在前端压缩图片并上传demo 如下截图&#xff1a; 点击文件选择框&#xff0c;我们不妨选一张尺寸比较大的图片&#xff0c;例如下面这种2M多的钓鱼收获照&#xff1a; 于是图片歘歘歘地传上去了&#xff1a; 此时我们点击最终…

JavaScript 图像压缩

JavaScript 可以使用类似于 canvas 和 web workers 来实现图像压缩。 使用 canvas&#xff0c;可以将图像绘制到 canvas 上&#xff0c;然后使用 canvas 提供的 toBlob() 或 toDataURL() 方法将其转换为不同格式的图像。在这些方法中指定图像质量参数即可实现压缩。 使用 web…

英文论文(sci)解读复现【NO.11】一种先进的基于深度学习模型的植物病害检测:近期研究综述

此前出了目标检测算法改进专栏&#xff0c;但是对于应用于什么场景&#xff0c;需要什么改进方法对应与自己的应用场景有效果&#xff0c;并且多少改进点能发什么水平的文章&#xff0c;为解决大家的困惑&#xff0c;此系列文章旨在给大家解读发表高水平学术期刊中的 SCI论文&a…

如何自己制作简历模板?简历在线制作的方法介绍

找工作时好看并有意义的简历是十分重要的事儿&#xff0c;如何制作一份出色的简历&#xff0c;在漫天的简历中脱颖而出呢&#xff1f;如何自己制作简历模板&#xff1f;今天七分简历--简历在线制作就来给大家介绍方法吧。 1.选用正确的简历模板 所谓正确的简历模板&#xff0c;…

怎么从手机上下载应聘简历模板?个人简历如何从手机做?

​当我们找工作时&#xff0c;一般都会先准备一份应聘简历&#xff0c;当我们投递简历或者面试时都会用到&#xff0c;那么如果想要用手机来制作一份简历时&#xff0c;该如何操作呢&#xff1f;想要制作简历&#xff0c;那么首先要下载一份自己喜欢的简历模板&#xff0c;会让…

手机怎么做个人简历?多行业简历模板自由选择

如何利用手机来制作简历呢&#xff1f;现在找工作的时候&#xff0c;大多会使用手机来查看各种招聘app软件的信息来选择自己喜欢的工作。那么为了能够更好的获取面试的机会&#xff0c;那么准备一份优质的个人简历是必不可少的&#xff0c;那么从手机上如何下载一个精美简历模板…

简历怎么制作?简历制作的步骤是什么?

制作简历最基础的工作就是先了解自己&#xff0c;知道自己的兴趣爱好和职业特长是什么&#xff0c;明确自己以后发展的方向&#xff0c;以此作为依据来制作简历。一份优秀的简历&#xff0c;一般分为以下6个部分。 1、基础信息 只需要介绍求职者的个人信息&#xff0c;如&…

简历编辑导出工具(类似wps简历助手)

目前支持简历的编辑&#xff0c;导出&#xff0c;模块化&#xff0c;顺序调整&#xff0c;导出样式选择&#xff0c;完成进度等功能&#xff0c;已经完全可以满足简历编辑的基本需求 在线体验地址&#xff1a;需要的可以私信我&#xff0c;避免网站被攻击 一.项目架构 前端&a…

wps怎么免费导出简历_WPS表格办公—一键添加简历模板

我们在利用WPS文字与Word文字进行日常办公时&#xff0c;经常需要输入各种各样文档&#xff0c;当我们毕业季需要面试的时候&#xff0c;一份干净简洁的简历就必不可少了&#xff0c;那么对于WPS小白来说&#xff0c;制作一份简历就太难了&#xff0c;没关系&#xff0c;WPS为大…

wps怎么免费导出简历_简历模板免费下载wps手机,简历模板免费下载wps可编辑

现在&#xff0c;无论您在哪里工作&#xff0c;都需要自己准备一份简历。履历代表一个人的形象。拥有良好的履历是踏脚石。只要您可以在一张简历中精简一下您的72种变化&#xff0c;就可以帮助您敲开雇主的门。如果您拥有出色的技能&#xff0c;却不知道如何向他人展示它&#…