preface

Today I’ll share how the front end compresses images.


First, compression method introduction

The front-end compression picture mainly uses the canvas method of toDataURL, which is actually to get the content on the canvas.

This method takes two parameters, the MDN interpretation is

Parameter Type Image format (image/ PNG by default) encoderOptions If the image format is image/ JPEG or image/webp, you can select the image quality from 0 to 1. If the value is out of range, the default value 0.92 will be used. Other parameters are ignored.

That is, the compressed image only supports the above two formats (compressed format) and other formats to try (the blogger tested PNG, but also the pressure is too big..).

This method returns a base64 image data

Data in File or Blob format is used in uploads, so base64 data needs to be processed as well


Second, compress the code

Js method

    // Image base64 data fetch
	const photoCompress = (file, compressedOption, callback) = > {
      let fileReader = new FileReader()
      fileReader.readAsDataURL(file)

      fileReader.onload = () = > {
        let fileResult = fileReader.result
        canvasDataURL(fileResult, compressedOption, callback)
      }
    }

	// Render the image to canvas and get the image of the specified quality
    const canvasDataURL = (path, compressedOption, callback) = > {
      let img = new Image()
      img.src = path
      img.onload = () = > {
        // Set the compressed image size
        let quality = compressedOption.quality
        let w = compressedOption.width || img.width

        // If only width exists, set the height according to the scale
        let h = compressedOption.height || (compressedOption.width ? compressedOption.width / (img.width / img.height) : ' ') || img.height

        / / generated canvas
        let canvas = document.createElement('canvas')
        let ctx = canvas.getContext('2d')

        // Set the width and height and render the image
        canvas.width = w
        canvas.height = h
        ctx.drawImage(img, 0.0, w, h)

        let base64 = canvas.toDataURL('image/jpeg', quality)
        // https://developer.mozilla.org/zh-CN/docs/Web/API/HTMLCanvasElement/toDataURL

        // The callback function returns the base64 value
        callback(base64)
      }
    }

	// Image transcoding
    const convertBase64UrlToFile = (urlData, filename) = > {
      let arr = urlData.split(', ')
      let mime = arr[0].match(/ : (. *?) ; /) [1]

      let bstr = atob(arr[1])
      // https://www.runoob.com/jsref/met-win-atob.html
      let n = bstr.length

      let u8arr = new Uint8Array(n)
      // https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array
      while (n--) {
        u8arr[n] = bstr.charCodeAt(n)
        // https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/String/charCodeAt
      }

      // return new Blob([u8arr], { type: mime })
      // https://developer.mozilla.org/zh-CN/docs/Web/API/Blob

      return new File([u8arr], filename, { type: mime })
      // https://developer.mozilla.org/zh-CN/docs/Web/API/File
    }

	// Get the DOM and register the event
    document.getElementById('inputeFile').addEventListener('change'.(e) = > {
      let file = e.target.files[0]

      photoCompress(
        file,
        {
          quality: 0.2.// width: 0,
          // height: 0
        },
        base64Codes= > {
          let newFile = convertBase64UrlToFile(base64Codes, file.name)

          console.log(newFile)
        }
      )
    })
Copy the code

HTML tags

	<input id="inputeFile" type="file" accept="image/*"/>
Copy the code

The transcoding in convertBase64UrlToFile function is normally used in the uplink port, and the uploading components of iView and Element-UI use the format of the transcoding results above.


Three,iview element-uiUpload processing

The iView source code, and the Element-UI source code have a before-upload hook. Before-upload: Hook before a file is uploaded. The upload is stopped if false or a Promise is returned and reject is rejected.

Here we need to return a Promise in this hook

ElementUI Upload component source upload function code

upload(rawFile) {
 this.$refs.input.value = null;

 // This is the hook for checking whether to pass props before uploading
 if (!this.beforeUpload) {
   return this.post(rawFile);
 }

 // We return Promise in this hook
 const before = this.beforeUpload(rawFile);
 
 if (before && before.then) {
   before.then(processedFile= > {
     const fileType = Object.prototype.toString.call(processedFile);
	
     // Upload returns a compressed image File. Iview only supports File format, not Blob format
     if (fileType === '[object File]' || fileType === '[object Blob]') {
       if (fileType === '[object Blob]') {
         processedFile = new File([processedFile], rawFile.name, {
           type: rawFile.type
         });
       }
       for (const p in rawFile) {
         if(rawFile.hasOwnProperty(p)) { processedFile[p] = rawFile[p]; }}this.post(processedFile);
     } else {
       this.post(rawFile); }},() = > {
     this.onRemove(null, rawFile);
   });
 } else if(before ! = =false) {
   this.post(rawFile);
 } else {
   this.onRemove(null, rawFile); }}Copy the code

Iview is the same as the elemental-UI source code, but the elemental-UI update is compatible with Blob format. Resolve (File)

Here is the code we will write in the project

<el-upload
  class="upload-demo"
  :before-update="beforeUpdate">
  <el-button size="small" type="primary">Click on the upload</el-button>
  <div slot="tip" class="el-upload__tip">Only JPG/PNG files can be uploaded, and the maximum size is 500kb</div>
</el-upload>
Copy the code
beforeUpdate (file, fileList) {
	return new Promise((resolve, reject) = > {
		
		// The compression function is what we wrote above
		photoCompress(
	        file,
	        {
	          quality: 0.2.// width: 0,
	          // height: 0
	        },
	        base64Codes= > {
	          let newFile = convertBase64UrlToFile(base64Codes, file.name)
	
			  resolve(newFile)
	        }
	    )
	})
}
Copy the code

The DEMO presentation

http://114.55.39.43/compressImage

conclusion

The method of compression is generally easy to understand. The complete process is to draw the original picture to canvas. Canvas uses toDataURL method to obtain compressed image data and finally transcodes it back to upload component for use

The above pre – upload compression is written, if there are omissions or errors welcome correction, thank you.