“Directory”

  • Source of problem
  • Thought analysis
  • Function of premise
    • Convert the file file to base64
    • Convert Base64 to a file stream
  • Compression method
  • Methods using
  • The problem summary
    • Image compression
    • I wanted to do a recursive compression of the image until it was the desired size
    • The direction of the ios camera is wrong

Source of problem

This problem is caused by the fact that the background limits the size of the image file to 2MB, but the size exceeds 2MB when the camera is switched on to take a picture. In order not to affect user experience and functional requirements, the front-end needs to compress the size and then upload the image to the background.

Thought analysis

After looking for a lot of materials, I found that only canvas can compress pictures.

2. Create an image tag to receive the file and obtain the width, height and proportion of the image. Create Canvas Canvas Set the canvas size. 4. Draw the image onto the canvas. 5. Compress canvas to obtain new baseURL 6. Convert baseURL back to file.

Function of premise

Convert the 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();
      // Return null if file is not defined
      if(file == undefined) return fn(null);
      // Read file and get base64 bits
      fileReader.readAsDataURL(file);
      fileReader.onload = function(){
        // 把读取到的base64
        var imgBase64Data = this.result; fn(imgBase64Data); }}Copy the code

Convert Base64 to a file stream

/** * Convert base64 to a 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});
 }
Copy the code

Compression method

/** * canvas compressed image *@param Obj} {parameter param 
* @param {file binary stream} Param. The file will be *@param {target compression size} Param. targetSize does not pass the initial assignment -1 *@param {output image width} Param. width does not pass an initial assignment of -1, and isometric scaling does not pass height *@param {output image name} Param. fileName does not pass the initial assignment image *@param {degree of compression} Param. quality Does not pass the initial value of 0.92. The value ranges from 0 to 1 *@param {callback function} Param. Succ will pass * /
function pressImg(param){
  // If there is no callback function, it is not executed
  if(param && param.succ){
     // Return null if file is not defined
     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 image file _ ^_^');
       return param.succ(null);
     }
     // If the current size is smaller than the target size, print it directly
     var size = param.file.size;
     if(param.targetSize > size){
       return param.succ(param.file);
     }
     // Read file and get base64 bits
     changeFileToBaseURL(param.file,function(base64){
       if(base64){
         var image = new Image();
         image.src = base64;
         image.onload = function(){
           // Get the width 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 is the original image width
           canvas.width = param.width == -1 ? this.width : param.width;
           // Get the height of the compressed image. If width is -1, the default height is the original image
           canvas.height = param.width == -1 ? this.height : parseInt(param.width / scale);
           // Draw the image to the canvas
           context.drawImage(image, 0.0, canvas.width, canvas.height);
           // Compress the image to get the new base64Url
           var newImageData = canvas.toDataURL(fileType,param.quality);
           // Convert Base64 to a file stream
           var resultFile = dataURLtoFile(newImageData,param.fileName);
           // determine if the targetSize is limited and the compressed image size is larger than the targetSize, an error is displayed
           if(param.targetSize ! = -1 && param.targetSize < resultFile.size){
             console.log("Image upload size is too big, please upload again.");
             param.succ(null);
           }else{
             // Returns the file streamparam.succ(resultFile); }}}}); }}Copy the code

Methods using

The file size is in bytes, so we need to convert the required size to bytes.

1byte is 1byte, 1KB is 1024B, and 1MB is 1024 x 1024B

<input type="file" id="fileImg" class="fileImg"/>
Copy the code
// Upload the image file to get the URL
$("#fileImg").on('change'.function(){
   pressImg({
     file:this.files[0].targetSize:2 * 1024 * 1024.quality:0.5.width:600.succ:function(resultFile){
         // If not null, the compression succeeded
         if(resultFile){
           //TODO}}})});Copy the code

The problem summary

Image compression

The compression degree of the picture is not easy to determine, so it can be repeated attempts to adjust according to the requirements of the demand side. Changing the size and sharpness of the target image can change the compression of the image.

I wanted to do a recursive compression of the image until it was the desired size

It turned out

  • If the target size is relatively small, how to compress the picture can not meet the conditions, it will cause the cycle can not jump out, waste resources.
  • If the image is compressed several times, the file size will not change, sometimes it will increase, weird.

So I gave up recursion.

The direction of the ios camera is wrong

Because ios turns the camera 90 degrees counterclockwise to take a picture. However, after I compressed the picture and sent it to the background, I found that the shooting direction of the exif information of the picture was lost, resulting in the counterclockwise rotation of the picture uploaded by ios of 90 degrees. That’s a problem Android hasn’t noticed.

It is suspected that base64 was lost when it was converted to file. The verification will be supplemented here.

Version1.0 — 2019-8-2 — Create “Compress image size using Canvas”

© burning_ rhyme groups