《猛戳-查看个人博客地图-总有你意想不到的惊喜》
本文内容:H5端相机拍照原理、图片压缩方法、onload事件异步方法的同步处理、onload事件
多个
异步方法的同步处理、使用react-cropper实现图片预览和裁剪、使用vue-cropper实现图片预览和裁剪、base64和blobjavascript
设置input标签的属性以下,capture为空会让用户选择本地文件或者拍照,onChange事件直接将图片文件转换为base64css
<html> <body> //react组件 <input type="file" onChange={(e)=>{this.onChange(e)}} className={styles.getImg} id="fileinput" ref='onChange' accept="image/*" capture="camera" /> </body> <script> onChange(e){ let file = e.currentTarget.files[0]; //console.log('图片原文件信息',file); let fReader=new FileReader(); fReader.readAsDataURL(file); fReader.onload=function(e) { console.log('图片转化成base64的大小',this.result.length/1024,'kb') } } </script> </html>
注意:Change事件触发有两个必要条件:值改变、失去焦点。因此从本地第二次选择同一张照片时,不触发。html
方案一:使用label元素来触发一个隐藏的file input元素
方案二:设置顶层input元素的透明度为零,设置底层元素为本身须要的可见样式,或者图片vue
//异步压缩方法 function asyncCompression(base64){ //初始化压缩率 0.1-表示将原图10M变成1M 10-表示将原图1M变成10M let compressionRatio = 0.1; let img = new Image(); img.src = base64; //异步 img.onload = function () { //生成比例 let width = img.width, height = img.height; console.log('图片原始宽高',width,height) //生成canvas let canvas = document.createElement("canvas"); let ctx = canvas.getContext("2d"); canvas.width = img.width; canvas.height = img.height; ctx.drawImage(img, 0, 0, img.width, img.height); //第一次粗压缩 let base64 = canvas.toDataURL('image/jpeg', compressionRatio); console.log('第一次粗压缩',base64.length/1024,'kb,压缩率',compressionRatio); //第二次细压缩 while(base64.length/1024 > 200 && compressionRatio > 0.05){ compressionRatio -= 0.01; base64 = canvas.toDataURL('image/jpeg', compressionRatio); console.log('第二次细压缩',base64.length/1024,'kb,压缩率',compressionRatio) } //第三次精细压缩 ... //压缩后的结果 返回base64 此处是异步返回 return base64 }; }
function promiseCompression(base64){ return new Promise((resolve,reject)=>{ //初始化压缩率 0.1-表示将原图10M变成1M 10-表示将原图1M变成10M let compressionRatio = 0.1; let img = new Image(); img.src = base64; //异步 img.onload = function () { //生成比例 let width = img.width, height = img.height; console.log('图片原始宽高',width,height) //生成canvas let canvas = document.createElement("canvas"); let ctx = canvas.getContext("2d"); canvas.width = img.width; canvas.height = img.height; ctx.drawImage(img, 0, 0, img.width, img.height); //第一次粗压缩 let base64 = canvas.toDataURL('image/jpeg', compressionRatio); console.log('第一次粗压缩',base64.length/1024,'kb,压缩率',compressionRatio); //第二次细压缩 while(base64.length/1024 > 200 && compressionRatio > 0.05){ compressionRatio -= 0.01; base64 = canvas.toDataURL('image/jpeg', compressionRatio); console.log('第二次细压缩',base64.length/1024,'kb,压缩率',compressionRatio) } //第三次精细压缩 ... //压缩后的结果 返回base64 resolve(base64) }; }) } //使用 promiseCompression(base64).then((res)=>{ //send data to server console.log('压缩后的base64',res) })
async function asyncCompression(base64) { //初始化压缩率 0.1-表示将原图10M变成1M 10-表示将原图1M变成10M let compressionRatio = 0.1; let img = new Image(); img.src = base64; //异步 img.onload = function () { //生成比例 let width = img.width, height = img.height; console.log('图片原始宽高',width,height) //生成canvas let canvas = document.createElement("canvas"); let ctx = canvas.getContext("2d"); canvas.width = img.width; canvas.height = img.height; ctx.drawImage(img, 0, 0, img.width, img.height); //第一次粗压缩 let base64 = canvas.toDataURL('image/jpeg', compressionRatio); console.log('第一次粗压缩',base64.length/1024,'kb,压缩率',compressionRatio); //第二次细压缩 while(base64.length/1024 > 200 && compressionRatio > 0.05){ compressionRatio -= 0.01; base64 = canvas.toDataURL('image/jpeg', compressionRatio); console.log('第二次细压缩',base64.length/1024,'kb,压缩率',compressionRatio) } //第三次精细压缩 ... //压缩后的结果 返回base64 return base64 }; } //使用 asyncCompression(base64).then((res)=>{ //send data to server console.log('压缩后的base64',res) })
多个
异步方法的同步处理function promiseCompression(base64){ return new Promise((resolve,reject)=>{ //初始化压缩率 0.1-表示将原图10M变成1M 10-表示将原图1M变成10M let compressionRatio = 0.1; let img = new Image(); img.src = base64; //异步 img.onload = function () { //生成比例 let width = img.width, height = img.height; console.log('图片原始宽高',width,height) //生成canvas let canvas = document.createElement("canvas"); let ctx = canvas.getContext("2d"); canvas.width = img.width; canvas.height = img.height; ctx.drawImage(img, 0, 0, img.width, img.height); //第一次粗压缩 let base64 = canvas.toDataURL('image/jpeg', compressionRatio); console.log('第一次粗压缩',base64.length/1024,'kb,压缩率',compressionRatio); //第二次细压缩 while(base64.length/1024 > 200 && compressionRatio > 0.05){ compressionRatio -= 0.01; base64 = canvas.toDataURL('image/jpeg', compressionRatio); console.log('第二次细压缩',base64.length/1024,'kb,压缩率',compressionRatio) } //第三次精细压缩 ... //压缩后的结果 返回base64 resolve(base64) }; }) } let promiseList = []; [1,2,3].forEach(()=>{ //三个异步等待同步同步 promiseList.push(promiseCompression(base64)) }) //使用 Promise.all(promiseList).then((res)=>{ //send data to server console.log('压缩后的base64',res) })
function promiseCompression(base64){ return new Promise((resolve,reject)=>{ //初始化压缩率 0.1-表示将原图10M变成1M 10-表示将原图1M变成10M let compressionRatio = 0.1; let img = new Image(); img.src = base64; //异步 img.onload = function () { //生成比例 let width = img.width, height = img.height; console.log('图片原始宽高',width,height) //生成canvas let canvas = document.createElement("canvas"); let ctx = canvas.getContext("2d"); canvas.width = img.width; canvas.height = img.height; ctx.drawImage(img, 0, 0, img.width, img.height); //第一次粗压缩 let base64 = canvas.toDataURL('image/jpeg', compressionRatio); console.log('第一次粗压缩',base64.length/1024,'kb,压缩率',compressionRatio); //第二次细压缩 while(base64.length/1024 > 200 && compressionRatio > 0.05){ compressionRatio -= 0.01; base64 = canvas.toDataURL('image/jpeg', compressionRatio); console.log('第二次细压缩',base64.length/1024,'kb,压缩率',compressionRatio) } //第三次精细压缩 ... //压缩后的结果 返回base64 resolve(base64) }; }) } async function asyncCompression() { let base64Data = ['1','2','3',] let base64List = []; base64List[0] = await promiseCompression(base64Data[0]); base64List[1] = await promiseCompression(base64Data[1]); base64List[2] = await promiseCompression(base64Data[2]); return base64List } //使用 asyncCompression().then((res)=>{ //send data to server console.log('压缩后的base64',res) })
//页面加载过程当中显示加载蒙层,当3个异步http请求都成功后,隐藏加载蒙层 this.asyncGetDataStatus = [false,false,false] componentDidMount(){ getDataFromDB01().then(res => { this.asyncGetDataStatus[0] = true; this.closeLoading(); }) getDataFromDB02().then(res => { this.asyncGetDataStatus[1] = true; this.closeLoading(); }) getDataFromDB03().then(res => { this.asyncGetDataStatus[2] = true; this.closeLoading(); }) } closeLoading(){ if(this.asyncGetDataStatus.every((item) => item)){ this.setState({displayLoading: false}) } }
import Cropper from 'react-cropper'; import 'cropperjs/dist/cropper.css'; getCropperData(){ //this.refs.cropper.getCropBoxData();//height left top width //this.refs.cropper.getCanvasData()//height left top width naturalHeight naturalWidth //this.refs.cropper.getImageData()//height left top width naturalHeight naturalWidth aspectRatio rotate scaleX scaleY //this.refs.cropper.getContainerData()//height width //this.refs.cropper.getData()//height width rotate scaleX scaleY x y return this.refs.cropper.getCroppedCanvas().toDataURL();//base64 } render(){ return <div> <Cropper className={styles.crop} ref='cropper' src={this.state.cropperData} style={{maxHeight: 400, width: '100%'}} //0-默认-没有任何限制 1-限制裁剪框不超过canvas画布边缘 2-若是是长图-限制图片不超过cropper的最高可视区域-同时裁剪框不超过canvas画布边缘 viewMode={2} dragMode='none' minCanvasWidth={285} //隐藏棋盘背景色 background={false} //裁剪框内部的横竖虚线可见 guides={true} //裁剪框内部的十字线可见 center={false} //可旋转原图 rotatable={true} //可缩放原图 scalable={true} //crop={(e)=>{this.crop(e)}} /> </div> }
import VueCropper from 'vue-cropper' Vue.use(VueCropper) getCropperData(){ // 获取截图的base64 数据 this.$refs.cropper.getCropData((data) => { // do something console.log(data) }) // 获取截图的blob数据 this.$refs.cropper.getCropBlob((data) => { // do something console.log(data) }) } <template> <vueCropper ref="cropper" :img="" :outputSize="" :outputType="" :info="" :full="" :canScale="" :canMove="" :canMoveBox="" :original="" :autoCrop="" :fixedBox="" :fixed="" @imgLoad="imgLoad"> </vueCropper> </template>
//base64的格式以下 let base64 = "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAFA3PEY8MlBGQUZaVVBfeMiCeG5uePWvuZHI////////////////////////////////////////////////////2wBDAVVaWnhpeOuCguv/////////////////////////////////////////////////////////////////////////wAARCAAmACcDASIAAhEBAxEB/8QAFgABAQEAAAAAAAAAAAAAAAAAAAEC/8QAGBABAQADAAAAAAAAAAAAAAAAAAIBEjH/xAAWAQEBAQAAAAAAAAAAAAAAAAAAAwL/xAAXEQEBAQEAAAAAAAAAAAAAAAAAAQIR/9oADAMBAAIRAxEAPwCgMLgAAAAHQAAAAAAAAZutcAKZk4lq2V//2Q==" function base64URLtoBlobUrl(base64){ const arr = base64.split(',');//['data:image/jpeg;base64','/9j/4AAQSkZJRgA...'] const mime = arr[0].match(/:(.*?);/)[1];//"image/jpeg" const bstr = atob(arr[1]) let n = bstr.length;//316 const u8arr = new Uint8Array(n);//Uint8Array(316) [255,216,255,224,0,16,74,70,73,70,0,1,1,0,0,1,0,1,0,0,255,219,0,67,0,80,55,60,70,60,50,80,70,65,70,90,85,80,95,120,200,130,120,110,110,120,245,175,185,145,200,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,219,0,67,1,85,90,90,120,105,120,235,130,130,235,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,192,0,17,8,0,38,0,39,3,1,34,0,2,17,1,3,17,1,255,196,0,22,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,255,196,0,24,16,1,1,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,2,1,18,49,255,196,0,22,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,2,255,196,0,23,17,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,17,255,218,0,12,3,1,0,2,17,3,17,0,63,0,160,48,184,0,0,0,7,64,0,0,0,0,0,1,155,173,112,2,153,147,137,106,217,95,255,217] while (n--) { u8arr[n] = bstr.charCodeAt(n) } const blob = new Blob([u8arr], { type: mime });//{size:316,type:"image/jpeg"} const src = window.URL.createObjectURL(blob) //"blob:http://0.0.0.0:3001/24704350-26e1-4a0e-82de-d8d5bb5d954a" return src } console.log(base64URLtoBlobUrl(base64)); //blob的格式以下 let u8arr = [255,216,255,224,0,16,74,70,73,70,0,1,1,0,0,1,0,1,0,0,255,219,0,67,0,80,55,60,70,60,50,80,70,65,70,90,85,80,95,120,200,130,120,110,110,120,245,175,185,145,200,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,219,0,67,1,85,90,90,120,105,120,235,130,130,235,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,192,0,17,8,0,36,0,36,3,1,34,0,2,17,1,3,17,1,255,196,0,21,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,255,196,0,23,16,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,17,33,49,255,196,0,22,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,255,196,0,20,17,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,218,0,12,3,1,0,2,17,3,17,0,63,0,160,33,184,0,45,12,1,0,232,0,2,224,64,16,0,0,0,0,127,255,217] const blob = new Blob(u8arr, { type: "image/jpeg" }) function blobToBase64Url(blob){ const promise = new Promise((resolve, reject) => { const file = new FileReader() file.readAsDataURL(blob) file.onload = e => { resolve(e.target.result) } }) return promise } blobToBase64Url(blob).then((res)=>{ console.log(res);//"data:image/jpeg;base64,MjU1MjE2MjU1MjI0MDE2NzQ3MDczNzAwMTEwMDEwMTAwMjU1MjE5MDY3MDgwNTU2MDcwNjA1MDgwNzA2NTcwOTA4NTgwOTUxMjAyMDAxMzAxMjAxMTAxMTAxMjAyNDUxNzUxODUxNDUyMDAyNTUyNTUyNTUyNTUyNTUyNTUyNTUyNTUyNTUyNTUyNTUyNTUyNTUyNTUyNTUyNTUyNTUyNTUyNTUyNTUyNTUyNTUyNTUyNTUyNTUyNTUyNTUyNTUyNTUyNTUyNTUyNTUyNTUyNTUyNTUyNTUyNTUyNTUyNTUyMTkwNjcxODU5MDkwMTIwMTA1MTIwMjM1MTMwMTMwMjM1MjU1MjU1MjU1MjU1MjU1MjU1MjU1MjU1MjU1MjU1MjU1MjU1MjU1MjU1MjU1MjU1MjU1MjU1MjU1MjU1MjU1MjU1MjU1MjU1MjU1MjU1MjU1MjU1MjU1MjU1MjU1MjU1MjU1MjU1MjU1MjU1MjU1MjU1MjU1MjU1MjU1MjU1MjU1MjU1MjU1MjU1MjU1MjU1MjU1MjU1MjU1MjU1MjU1MjU1MjU1MTkyMDE3ODAzNjAzNjMxMzQwMjE3MTMxNzEyNTUxOTYwMjEwMTEwMDAwMDAwMDAwMDAwMDAxMjU1MTk2MDIzMTYxMTExMDAwMDAwMDAwMDAwMDE3MzM0OTI1NTE5NjAyMjExMTEwMDAwMDAwMDAwMDAwMDIzMjU1MTk2MDIwMTcxMDAwMDAwMDAwMDAwMDAwMDI1NTIxODAxMjMxMDIxNzMxNzA2MzAxNjAzMzE4NDA0NTEyMTAyMzIwMjIyNDY0MTYwMDAwMTI3MjU1MjE3" })
设置input标签的属性以下,capture为空会让用户选择本地文件或者拍照,onChange事件直接将图片文件转换为base64java
<html> <body> <input className={styles.courseSaleInfoUpload} type='file' accept="image/*" onChange={(e)=>{this.uploadImageHandleChange(e,0)}} /> </body> <script> beforeUpload = (file) => { const isIMG = ['image/jpeg','image/jpeg','image/png'].indexOf(file.type) != -1; if (!isIMG) { message.error('只能上传jpg、jpeg、png类型的图片'); } const isLt2M = file.size / 1024 / 1024 < 2; if (!isLt2M) { message.error('图片大小不能超过2MB!'); } return isIMG && isLt2M; } uploadImageHandleChange(e,index){ let _this = this; let generalInfo = this.props.data.courseProductBasicInfo let file = e.currentTarget.files[0]; if(!this.beforeUpload(file)){ return } let fReader=new FileReader(); fReader.readAsDataURL(file); fReader.onload=function() { console.log(this.result); } }; </script> </html>
感谢阅读,欢迎评论^-^react
打赏我吧^-^