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-ui
Upload 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.