Background:

Recently, the project needs to use the base64 image format and compress the pictures uploaded by users, so I plan to write a method of image selection, compression and conversion by myself (it needs to be compressed to a specified size).

Ideas:

  1. The reader. ReadAsDataURL (img) method of FileReader is called to read the image information.
  2. In the reader.onload event, create a new Image object and assign the reader.result value to img. SRC. Canvs is used to compress the image to the appropriate size.

Now that I have the idea, I’m ready to try it out…

  1. The first step is to introduce the dependency file required by the project. Because I did it locally and directly with native JS when WRITING, I used CDN to introduce it.

    <script src="https://cdn.jsdelivr.net/npm/exif-js"></script>
    Copy the code
  2. Create projects and write basic code

    <! DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, < span style>. Ui_button {background: #0066cc; color: #fff; padding: 10px 20px; margin: 10px; display: block; width: 100px; text-align: center; cursor: pointer; border-radius: 5px; } img { height: 100px; width: 100px; display: none; </style> </head> <body> <label class="ui_button" for="xFile" label> </label> <form> <input type="file" accept="image/*" onchange="fileChange(this)" style="position: absolute; clip: rect(0 0 0 0)" /> </form> <img src="" alt="" id="showImg" /> </body> <script src="https://cdn.jsdelivr.net/npm/exif-js"></script> </html>Copy the code
  3. Start to write the method of obtaining pictures and processing pictures (the general idea and logic are as follows)

    1. First get the button and input and add a click event to the button, and trigger the input click event to select the file.
    2. Defines the imageCompression file compression method that takes three parameters (file file, callBack callBack after processing, params {parameters needed to draw canvas, size of imageCompression, format of returned file})
    3. The FileReader method is required, so before processing, check whether the browser supports the file and print an error message. If the browser supports the file, use FileReader to read the incoming file
    4. Create the IMG in the filereader.onload method,
    5. Listen for the img.onload event to draw the canvas after the image is loaded
    6. After drawing, we need to determine whether the image needs to be rotated according to the orientation value
    7. After the image is rotated properly, use recursion to compress the breakthrough to the set size
    Function imageCompression(file, callBack = () => {}, params = {width: 1000, LIMIT_SIZE: 0.5 * 1024 * 2014, isBase64: true, } ) { let compressCount = 0; const { width, LIMIT_SIZE, isBase64 } = params; const orientation = EXIF.getTag(file, "Orientation") || 1; Const errorFn = (e) => {console.error(" error ", e); // Const errorFn = (e) => {console.error(" error ", e); callBack(file); }; if (! Window.filereader) {console.error(" browsers do not support window.filereader "); callBack(file); } else { try { let reader = new FileReader(); reader.readAsDataURL(file); reader.onload = function () { let img = new Image(); img.src = reader.result; img.onload = function () { try { const canvas = document.createElement("canvas"); const context = canvas.getContext("2d"); const canvasWidth = width; const canvasHeight = canvasWidth / (img.width / img.height); canvas.width = canvasWidth; canvas.height = canvasHeight; let angle = 0; switch (orientation) { case 1: break; Case 6: // If Angle = (90 * math.pi) / 180; if Angle = (90 * math.pi) / 180; canvas.width = canvasHeight; canvas.height = canvasWidth; context.rotate(angle); context.translate(0, -canvas.width); break; Case 8: // Angle = (270 * math.pi) / 180; case 8: // Angle = (270 * math.pi) / 180; canvas.width = canvasHeight; canvas.height = canvasWidth; context.rotate(angle); context.translate(-canvas.height, 0); break; Case 3: // Angle = (180 * math.pi) / 180; case 3: // Angle = (180 * math.pi) / 180; canvas.width = canvasWidth; canvas.height = canvasHeight; context.rotate(angle); context.translate(-canvas.width, -canvas.height); break; default: break; } context.drawImage(img, 0, 0, canvasWidth, canvasHeight); context.setTransform(1, 0, 0, 1, 0, 0); canvas.toBlob( (blob) => { if (blob.size > LIMIT_SIZE) { compressCount += 1; imageCompression(blob, callBack); } else { compressCount = 0; if (isBase64) { callBack(canvas.toDataURL( 'image/png', 1 )); } else { callBack(blob); }}, "image/jpeg", 0.9 - compressCount * 0.1); } catch (error) { errorFn(error); }}; }; reader.onerror = (error) => { errorFn(error); }; } catch (error) { errorFn(error); }}}Copy the code
  4. Example code, copy to the page can directly view the effect

    <! DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, < span style>. Ui_button {background: #0066cc; color: #fff; padding: 10px 20px; margin: 10px; display: block; width: 100px; text-align: center; cursor: pointer; border-radius: 5px; } img { height: 100px; width: 100px; display: none; </style> </head> <body> <label class="ui_button" for="xFile" label> </label> <form> <input type="file" accept="image/*" onchange="fileChange(this)" style="position: absolute; clip: rect(0 0 0 0)" /> </form> <img src="" alt="" id="showImg" /> </body> <script src="https://cdn.jsdelivr.net/npm/exif-js"></script> <script> let btn = document.getElementsByClassName("ui_button")[0];  let fileInput = document.getElementsByTagName("input")[0]; btn.onclick = function () { fileInput.click(); }; function fileChange(e) { let file = e.files[0]; If (file.size > 4 * 1024 * 1024) {console.log(" Image too big to upload "); } else { imageCompression(file, getBase64); } } function imageCompression( file, callBack = () => {}, params = { width: 1000, LIMIT_SIZE: 0.5 * 1024 * 2014, isBase64: true,}) {let compressCount = 0; const { width, LIMIT_SIZE, isBase64 } = params; const orientation = EXIF.getTag(file, "Orientation") || 1; Const errorFn = (e) => {console.error(" error ", e); // Const errorFn = (e) => {console.error(" error ", e); callBack(file); }; if (! Window.filereader) {console.error(" browsers do not support window.filereader "); callBack(file); } else { try { let reader = new FileReader(); reader.readAsDataURL(file); reader.onload = function () { let img = new Image(); img.src = reader.result; img.onload = function () { try { const canvas = document.createElement("canvas"); const context = canvas.getContext("2d"); const canvasWidth = width; const canvasHeight = canvasWidth / (img.width / img.height); canvas.width = canvasWidth; canvas.height = canvasHeight; let angle = 0; switch (orientation) { case 1: break; Case 6: // If Angle = (90 * math.pi) / 180; if Angle = (90 * math.pi) / 180; canvas.width = canvasHeight; canvas.height = canvasWidth; context.rotate(angle); context.translate(0, -canvas.width); break; Case 8: // Angle = (270 * math.pi) / 180; case 8: // Angle = (270 * math.pi) / 180; canvas.width = canvasHeight; canvas.height = canvasWidth; context.rotate(angle); context.translate(-canvas.height, 0); break; Case 3: // Angle = (180 * math.pi) / 180; case 3: // Angle = (180 * math.pi) / 180; canvas.width = canvasWidth; canvas.height = canvasHeight; context.rotate(angle); context.translate(-canvas.width, -canvas.height); break; default: break; } context.drawImage(img, 0, 0, canvasWidth, canvasHeight); context.setTransform(1, 0, 0, 1, 0, 0); canvas.toBlob( (blob) => { if (blob.size > LIMIT_SIZE) { compressCount += 1; imageCompression(blob, callBack); } else { compressCount = 0; if (isBase64) { callBack(canvas.toDataURL( 'image/png', 1 )); } else { callBack(blob); }}, "image/jpeg", 0.9 - compressCount * 0.1); } catch (error) { errorFn(error); }}; }; reader.onerror = (error) => { errorFn(error); }; } catch (error) { errorFn(error); Function getBase64(base64) {let showImg = document.getelementById ("showImg"); showImg.src = base64; showImg.style.display = "block"; console.log(base64); } </script> </html>Copy the code
  5. rendering