This problem stems from the fact that when uploading image files, the background limits the size to 2MB, but when the camera is turned on to take pictures, it exceeds 2MB every minute. In order not to affect the user experience and functional requirements, the front-end needs to compress the size and then upload it. Go backstage.
Idea analysisAfter searching a lot of information, I found that only canvas can compress images.
The principle is roughly as follows: 1. First convert the file file of the image into baseURL. 2. Create an image tag to receive the file and obtain the width, height and proportion of the image. 3. Create a canvas and set the size of the canvas. 4. Draw the picture onto the canvas. 5. Compress the canvas and obtain a new baseURL. 6. Convert the baseURL back to a file.
function of premise Convert file file to base64/*** @param {binary file stream} file * @param {callback function, return base64} fn */function changeFileToBaseURL(file,fn){ // Create a read file object var fileReader = new FileReader(); // If file is not defined, return null if(file == undefined) return fn(null); // Read the file file, the result is base64-bit fileReader.readAsDataURL(file); fileReader.onload = function(){ // Read the base64 var imgBase64Data = this.result; fn(imgBase64Data); } }Convert base64 to file stream
/** * Convert base64 to file * @param {baseURL} dataurl * @param {file name} filename * @return {file binary stream}*/function dataURLtoFile(dataurl, filename) { var 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}); }Compression method
/*** canvas compressed image* @param {parameter obj} param * @param {file binary stream} param.file required* @param {target compression size} param.targetSize does not pass initial assignment -1* @param {output Image width} param.width does not pass the initial assignment value -1, and does not pass the height for proportional scaling* @param {output image name} param.fileName does not pass the initial assignment image* @param {compressed image degree} param.quality does not pass the initial assignment value of 0.92. Value range 0~1* @param {callback function} param.succ required */function pressImg(param){ //If there is no callback function, it will not be executed if(param && param.succ){ //If file is not defined, return null if(param.file == undefined) return param.succ(null); //Attach an initial value to the parameter param.targetSize = param.hasOwnProperty(targetSize)? param.targetSize : -1; param.width = param.hasOwnProperty(width) ? param.width : -1; param.fileName = param.hasOwnProperty(fileName) ? param.fileName: image; param.quality = param.hasOwnProperty( quality) ? param.quality : 0.92; var _this = this; // Get the file type var fileType = param.file.type; // console.log(fileType) //image/jpeg if(fileType.indexOf(image) == -1){ console.log('Please select an image file^_^'); return param.succ(null); } //If the current size is smaller than the target size, directly output var size = param.file.size; if(param.targetSize > size){ return param.succ(param.file); } / / Read the file file and the result is base64 changeFileToBaseURL(param.file,function(base64){ if(base64){ var image = new Image(); image.src = base64; image.onload = function(){ / / Get the aspect ratio var scale = this.width / this.height; // console.log(scale); //Create a canvas var canvas = document.createElement('canvas'); //Get the context var context = canvas.getContext('2d'); //Get the compressed image width. If width is -1, the default original image width canvas.width = param.width == -1? this.width : param.width; //Get the compressed image height. If width is -1, the default original image height is canvas.height = param.width == -1? this.height: parseInt(param.width / scale); //Draw the image onto the canvas context.drawImage(image, 0, 0, canvas.width, canvas.height); //Compress the image and obtain a new base64Url var newImageData = canvas .toDataURL(fileType,param.quality); //Convert base64 into a file stream var resultFile = dataURLtoFile(newImageData,param.fileName); //Judge if targetSize is limited and the compressed image size is larger than the target size, an error will pop up if(param.targetSize != -1 && param.targetSize < resultFile.size){ console .log(The image upload size is too large, please re-upload^_^); param.succ(null); }else{ //Return file stream param.succ(resultFile); } } } }); } }Method usage
The size of the file is in bytes, so we need to convert the required size into bytes. 1 byte is 1 byte is 1B, 1KB = 1024B, 1MB = 1024 * 1024B
<input type=file id=fileImg class=fileImg/>
//Get image file upload url$(#fileImg).on('change',function(){ pressImg({ file:this.files[0], targetSize:2 * 1024 * 1024, quality:0.5, width:600 , succ:function(resultFile){ //If it is not null, the compression is successful if(resultFile){ //TODO } } })});Problem summary Image compression level
The degree of compression of the image is not easy to determine, so you can try it many times and adjust it according to the requirements of the demander. Changing the size and resolution of the target image can change the degree of image compression.
Originally I wanted to do a recursive process of compressing images until the image size meets expectations.Later found out
Because when ios calls up the system camera to take pictures, it is rotated 90 degrees counterclockwise. After I compressed the image and sent it to the background, I found that the shooting direction of the exif information of the image was lost, causing the images uploaded by iOS to be rotated 90 degrees counterclockwise. Android has never noticed this problem.
At present, there is some suspicion that it was lost when base64 was converted into a file file. Additional instructions will be provided here after verification.
@version1.0-2019-8-2-Create "Use canvas to compress image size"
©burning_Yun Qiqi
The above is the entire content of this article. I hope it will be helpful to everyone’s study. I also hope everyone will support VeVb Wulin Network.