background:
(1) There is a problem that the uniapp image upload is too large and takes a long time to upload. The image needs to be compressed and uploaded.
(2) The image compression ratio varies with the size.
This article uses uniapp’s uni-file-picker to upload pictures, and uview’s picture upload can also be used for reference.
1. Image compression first install compressorjs
npm install compressorjs --save
2. Create imageCompress.js and use image compression. The type returned after compression in this article is blob
import Compressor from 'compressorjs'; // Only images in jpeg format can be converted /** * @param image image * @param backType The type blob, file that needs to be returned * @param quality Image compression ratio 0-1, the smaller the number, the smaller the image compression * @returns */ export default function ImageCompressor(image, backType, quality) { return new Promise((resolve, reject) => { new Compressor(image, { quality: quality || 0.6, success(result) { let file = new File([result], image.name, { type: image.type }) if (!backType || backType == 'blob') { resolve(result) } else if (backType == 'file') { resolve(file) } else { resolve(file) } }, error(err) { console.log('Image compression failed ---->>>>>', err) reject(err) } }) }) }
3. Create ConvertImage.js to convert non-jpeg images into jpeg images
// The idea is to create a picture, set the file equal to the picture, then create a canvas layer, scale the canvas proportionally, //Then use the drawImage of the canvas to combine the picture with the canvas, and then convert the base64 of the canvas into a file export default function ConvertImage(file) { return new Promise((resolve, reject) => { const fileName = file.name.substring(0, file.name.indexOf('.')); let reader = new FileReader(); //read file reader.readAsDataURL(file); reader. onloadend = function (e) { let image = new Image() //Create a new img tag (not yet embedded in the DOM node) image.src = e.target.result //Set the path of the image to the file path image.onload = function () { let canvas = document. createElement('canvas'), context = canvas. getContext('2d'), imageWidth = image. width, imageHeight = image. height, data = '' canvas.width = imageWidth canvas.height = imageHeight context. drawImage(image, 0, 0, imageWidth, imageHeight) data = canvas.toDataURL('image/jpeg') var newfile = dataURLtoFile(data, fileName + '.jpeg'); resolve(newfile) } } }) } function dataURLtoFile(dataurl, filename) { // base64 to file object let arr = dataurl. split(','), mime = arr[0].match(/:(.*?);/)[1], bstr = atob(arr[1]), n = bstr. length, u8arr = new Uint8Array(n); while (n--) { u8arr[n] = bstr. charCodeAt(n); } return new File([u8arr], filename, { type: mime }); // converted to jpeg format }
4. Compression ratio calculation
getCompressionRatio(fileSize) { const multiple = (fileSize / this.fileMaxSize).toFixed(2) // Get the file size multiple and generate quality ratio alert(fileSize + "===" + this.fileMaxSize + "===" + multiple) let compressionRatio = 1 if(multiple > 5) { compressionRatio = 0.5 } else if (multiple > 4) { compressionRatio = 0.6 } else if (multiple > 3) { compressionRatio = 0.7 } else if (multiple > 2) { compressionRatio = 0.8 } else if (multiple > 1) { compressionRatio = 0.9 } else { compressionRatio = 2 } return compressionRatio; },
5. blob to bloburl
Use uni.uploadFile to upload files, filePath uses the local address of bloburl, blob:http://localhost:9092/e9a9042b-feab-4fed-99ff-81c1e6efdece
uni.uploadFile({ url: '/prod-api/common/upload', //backend interface for processing images and returning image addresses filePath:tempFilePath, ... })
Therefore, it is necessary to convert the compressed blob file into bloburl so that it can be displayed and uploaded
let url = window. URL. createObjectURL(newImg)
6. The whole code is as follows
<template> <view class="u-page"> <view class="u-demo-block"> <view class="u-demo-block__content"> <!-- Note, if you need to be compatible with WeChat applets, it is best to set the rules rules through the setRules method --> <u--form labelPosition="left" :model="form" ref="form1" > <u-form-item label="Select Photo" prop="form.problemDescription" borderBottom labelWidth="80" ref="item3" > <uni-file-picker :source-type="sourceType" :sizeType="sizeType" v-model="fileList1" mode="grid" @select="select" @progress="progress" @success="success" @delete ="deletephoto" @fail="fail" ref="upload" limit="9" /> </uni-file-picker> </u-form-item> </u--form> </view> </view> </view> </template> <script> import { getToken } from "@/utils/auth"; import ImageCompressor from "@/utils/imageCompressor" import ConvertImage from "@/utils/ConvertImage" export default { data() { return { sourceType: ['album', 'camera'], timer: '', sizeType: ['compressed'], fileMaxSize: 2 * 1024 * 1024, // The default maximum is 2M fileMinSize: 50 * 1024, // The minimum is 50KB form: {}, fileList1: {}, imgSrc:{}, images: [], } }, onReady() { }, mounted() { // this. nowTimes() }, onLoad(option) { \t\t }, methods: { \t\t // // Select upload trigger function async select(e) { // According to the number of selected pictures, call the upload function multiple times console.log(e.tempFilePaths) let promises = [] for (let i = 0; i < e. tempFilePaths. length; i ++ ) { let img=e.tempFiles[i].file const fileSize = img. size const fileName = img.name'' if (fileSize > this. fileMaxSize) { const compressionRatio = this. getCompressionRatio(fileSize) if (compressionRatio > 1) { uni.$u.toast('file' + fileName + 'greater than 10M') return false } const fileType = img.name.substring(img.name.indexOf('.') + 1); // Determine whether the file is jpeg or not, convert it to jpeg if (!['jpeg', 'jpg'].includes(fileType)) { console. log(fileType) img = await ConvertImage(img); // convert the file in jpeg format } console. log(img) let newImg = await ImageCompressor(img, 'blob', compressionRatio); //image compression \t\t\t let url = window. URL. createObjectURL(newImg) const promise = this. uploadFiles(url) promises. push(promise) } } Promise.all(promises).then(()=>{ }) }, \t\t\t getCompressionRatio(fileSize) { const multiple = (fileSize / this.fileMaxSize).toFixed(2) // Get the file size multiple and generate quality ratio alert(fileSize + "===" + this.fileMaxSize + "===" + multiple) let compressionRatio = 1 if(multiple > 5) { compressionRatio = 0.5 } else if (multiple > 4) { compressionRatio = 0.6 } else if (multiple > 3) { compressionRatio = 0.7 } else if (multiple > 2) { compressionRatio = 0.8 } else if (multiple > 1) { compressionRatio = 0.9 } else { compressionRatio = 2 } return compressionRatio; }, // upload function async uploadFiles(tempFilePath){ let that=this await uni.uploadFile({ url: '/prod-api/common/upload', //backend interface for processing images and returning image addresses filePath:tempFilePath, name: 'file', header: { Authorization: "Bearer " + getToken(), }, success: res => { let data=JSON.parse(res.data) //The returned string needs to be converted into an object format let imageName=data.fileName that.images.push(imageName) uni.showToast({ title: 'Uploaded successfully', icon: "success" }); }, fail: () => { console.log("err"); uni.showToast({ title: 'Upload failed', icon: "error" }); } }) }, // remove image function async deletephoto(){ this.fileList1 = {} } } } </script>