100字范文,内容丰富有趣,生活中的好帮手!
100字范文 > 手把手教你实现一个图片压缩工具(Vue与Node的完美配合)

手把手教你实现一个图片压缩工具(Vue与Node的完美配合)

时间:2019-12-14 01:16:54

相关推荐

手把手教你实现一个图片压缩工具(Vue与Node的完美配合)

前言

图片压缩对于我们日常生活来讲,是非常实用的一项功能。有时我们会在在线图片压缩网站上进行压缩,有时会在电脑下软件进行压缩。那么我们能不能用前端的知识来自己实现一个图片压缩工具呢?答案是有的。

效果展示

原图片大小:82KB

压缩后的图片大小:17KB

测试

是不是特别good!!!看到上面的压缩后的图片,可能你还会质疑图片的清晰度,那么看下面(第一张图为压缩后的图片):

教程

这么好的工具,那我们来看看怎么用代码实现它。首先你可能需要一些Vue.js和Node.js的基础,另外你可能还需要一点对知识的渴望~ 哈哈哈。

话不多说,我们来上干货。

前台搭建

<template><div class="face"><label for="file" class="inputlabelBox"><inputtype="file"ref="pic"id="file"name="face"accept="image/*"capture="camera":style="{ display: 'none' }"@change="handleClick"/><div class="upload">上传图片</div></label><div class="imgbox" v-show="imgsrc != ''"><img src id="imgs" alt /></div><div><p class="upload" @click="keepImg" v-show="imgsrc != ''">确定</p></div></div></template><script>import EXIF from "exif-js";export default {name: "imgzip",data() {return {imgsrc: "",};},methods: {// 上传图片handleClick() {if (this.$refs.pic.files[0]) {// this.fileToBase64(this.$refs.pic.files[0]).then((res) => {// this.imgsrc = res;// });this.rotateImg(this.$refs.pic.files[0]).then((res) => {this.imgsrc = res;});}},// 压缩和图片旋转rotateImg(imgFile) {return new Promise((resolve) => {EXIF.getData(imgFile, function () {let exifTags = EXIF.getAllTags(this);let reader = new FileReader();reader.readAsDataURL(imgFile);reader.onload = (e) => {let imgData = e.target.result;document.querySelector("#imgs").src = e.target.result;// 8 表示 顺时针转了90// 3 表示 转了 180// 6 表示 逆时针转了90if (exifTags.Orientation == 8 ||exifTags.Orientation == 3 ||exifTags.Orientation == 6) {//翻转//获取原始图片大小const img = new Image();img.src = imgData;img.onload = function () {let cvs = document.createElement("canvas");let ctx = cvs.getContext("2d");//如果旋转90if (exifTags.Orientation == 8 || exifTags.Orientation == 6) {cvs.width = img.height;cvs.height = img.width;} else {cvs.width = img.width;cvs.height = img.height;}if (exifTags.Orientation == 6) {//原图逆时针转了90, 所以要顺时针旋转90ctx.rotate((Math.PI / 180) * 90);ctx.drawImage(img,0,0,img.width,img.height,0,-img.height,img.width,img.height);}if (exifTags.Orientation == 3) {//原图逆时针转了180, 所以顺时针旋转180ctx.rotate((Math.PI / 180) * 180);ctx.drawImage(img,0,0,img.width,img.height,-img.width,-img.height,img.width,img.height);}if (exifTags.Orientation == 8) {//原图顺时针旋转了90, 所以要你时针旋转90ctx.rotate((Math.PI / 180) * -90);ctx.drawImage(img,0,0,img.width,img.height,-img.width,0,img.width,img.height);}let data = cvs.toDataURL("image/jpeg"); // 输出压缩后的base64let arr = data.split(","),mime = arr[0].match(/:(.*?);/)[1], // 转成blobbstr = atob(arr[1]),n = bstr.length,u8arr = new Uint8Array(n);while (n--) {u8arr[n] = bstr.charCodeAt(n);}let files = new window.File([new Blob([u8arr], { type: mime })],"test.jpeg",{ type: "image/jpeg" });resolve(files);};} else {let image = new Image(); //新建一个img标签(还没嵌入DOM节点)image.src = e.target.result;image.onload = function () {let canvas = document.createElement("canvas"), // 新建canvascontext = canvas.getContext("2d"),imageWidth = image.width, //压缩后图片的大小imageHeight = image.height,data = "";canvas.width = imageWidth;canvas.height = imageHeight;context.drawImage(image, 0, 0, imageWidth, imageHeight);data = canvas.toDataURL("image/jpeg"); // 输出压缩后的base64let arr = data.split(","),mime = arr[0].match(/:(.*?);/)[1], // 转成blobbstr = atob(arr[1]),n = bstr.length,u8arr = new Uint8Array(n);while (n--) {u8arr[n] = bstr.charCodeAt(n);}let files = new window.File([new Blob([u8arr], { type: mime })],"test.jpeg",{ type: "image/jpeg" }); // 转成fileresolve(files);};}};});});},/*fileToBase64(file) {let that = this,reader = new FileReader();reader.readAsDataURL(file);return new Promise((resolve, reject) => {reader.onload = function (e) {//这里是一个异步,所以获取数据不好获取在实际项目中,就用new Promise解决if (this.result) {let image = new Image(); //新建一个img标签(还没嵌入DOM节点)image.src = e.target.result;document.querySelector("#imgs").src = e.target.result;image.onload = function () {let canvas = document.createElement("canvas"), // 新建canvascontext = canvas.getContext("2d"),imageWidth = image.width / 2, //压缩后图片的大小imageHeight = image.height / 2,data = "";canvas.width = imageWidth;canvas.height = imageHeight;context.drawImage(image, 0, 0, imageWidth, imageHeight);data = canvas.toDataURL("image/jpeg"); // 输出压缩后的base64let arr = data.split(","),mime = arr[0].match(/:(.*?);/)[1], // 转成blobbstr = atob(arr[1]),n = bstr.length,u8arr = new Uint8Array(n);while (n--) {u8arr[n] = bstr.charCodeAt(n);}let files = new window.File([new Blob([u8arr], { type: mime })],"test.jpeg",{ type: "image/jpeg" }); // 转成fileresolve(files);};} else {reject("err");}};});},*/// 保存图片keepImg() {// this.$emit("canvasToImage", this.imgsrc);const fd = new FormData();fd.append("file", this.imgsrc);fetch("http://localhost:6300/upload", {method: "post",mode:"cors",body:fd,}).then((response) => response.json()).then((response) => {if(response.success){console.log(this.imgsrc);const size = this.imgsrc.size<1024?this.imgsrc.size+"字节":Math.round(this.imgsrc.size/1024)+"KB";console.log(size);alert(`图片${response.name}${response.msg}!压缩后图片大小为:${size}。`);}}).catch((err) => {console.log(err);});},},};</script><style scoped lang="less">.upload {display: inline-block;background: #ffb90f;color: white;font-size: 16px;text-align: center;border-radius: 4px;padding: 10px 30px;margin-bottom: 20px;}.upload:hover {filter: brightness(110%);}.upload:active {filter: brightness(60%);}.imgbox {text-align: center;width: 60%;margin: 0 auto;img {width: 100%;height: 60vh;object-fit: contain;}}.face {margin-top: 30px;.container1 {background: #000;position: relative;width: 580px;height: 436px;margin: 0 auto;#canvas1 {position: absolute;}video,#canvas,#canvas1 {position: absolute;top: 0;left: 0;right: 0;bottom: 0;width: 581px;height: 436px;}}.btns {padding: 10px;button {margin: 20px 20px 20px 0;}}.tips {font-size: 26px;color: #666;margin: 10px 0;line-height: 48px;}.imgs {p {font-size: 28px;}}}</style>

我在这里实现了一个Vue组件(所以你得知道Vue是什么?组件又是什么?)。知道这些还不够,你还要知道怎么从依赖库下载依赖,这里需要另外下载的依赖是exif-js

一个JavaScript库,用于从图像文件中读取EXIF元数据。

您可以通过图像或文件输入元素在浏览器中的图像上使用它。EXIF和IPTC元数据均被检索。该软件包还可以在AMD或CommonJS环境中使用。

备注;使用exif.js依赖的作用是 为了防止在IOS系统中拍照上传图片旋转90度问题。

后台搭建

const Koa = require('koa');// koa框架const Router = require('koa-router');// 接口必备const cors = require('koa2-cors'); // 跨域必备const fs = require('fs'); // 文件系统const koaBody = require('koa-body'); //文件保存库const path = require('path'); // 路径let app = new Koa();let router = new Router();// 跨域app.use(cors({origin: function (ctx) {return ctx.header.origin;},exposeHeaders: ['WWW-Authenticate', 'Server-Authorization'],maxAge: 5,credentials: true,withCredentials: true,allowMethods: ['GET', 'POST', 'DELETE'],allowHeaders: ['Content-Type', 'Authorization', 'Accept'],}));//上传文件限制app.use(koaBody({multipart: true,formidable: {maxFileSize: 1000 * 1024 * 1024 // 设置上传文件大小最大限制,默认10M}}));// 上传图片router.post('/upload', async (ctx, next) => {if (ctx.request.files.file) {var file = ctx.request.files.file;// 创建可读流var reader = fs.createReadStream(file.path);// 修改文件的名称var myDate = new Date();var newFilename = myDate.getTime() + '.' + file.name.split('.')[1];var targetPath = path.join(__dirname, './images/') + `${newFilename}`;//创建可写流var upStream = fs.createWriteStream(targetPath);// 可读流通过管道写入可写流reader.pipe(upStream);ctx.body = {success: true,name: newFilename,msg:"压缩成功"};}});app.use(router.routes()).use(router.allowedMethods());app.listen(6300)console.log('服务器运行中')

后台的逻辑其实很简单,就是实现一个接口,接收前台发来的文件,保存到本地目录上以及返回给前台状态。

结语

谢谢你的浏览,如果还有需要优化的地方请及时留言哦~

欢迎关注我的公众号「前端历劫之路

回复关键词「电子书」,即可获取近12本前端热门电子书。

回复关键词「红宝书第4版」,即可获取最新《JavaScript高级程序设计》(第四版)电子书。

你还可以加我微信,我拉拢了很多IT大佬,创建了一个技术交流、文章分享群,欢迎你的加入。

作者:Vam的金豆之路

主要领域:前端开发

我的微信:maomin9761

微信公众号:前端历劫之路

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。