Node.js学习第九天笔记之切图功能

1 切图

  • 图像的裁切功能
    • 前提条件:下载安装GraphicsMagick
    • 模块:第三方模块gm模块;
    • 步骤:
      1. 引入模块;引入gm模块;var gm = require('gm');
      2. 使用gm();
        • gm括号中为需要裁切的图片的地址,
        • resize()为裁切后的宽高,里面设置"!",则为强制,按照设置大小生成文件,否则,等比例生成文件;
        • crop()为裁切的尺寸,分别为宽,高,左边距,上边距;
        • write("path",function(err){}):指的是生成文件放置的地址和名称,匿名函数中设置裁切成功后的操作;
        • 代码:
         var gm = require('gm');
         gm("./img/meinv.jpg")
             .crop(240,100,720,415)
             .resize(200, 200,"!")//强制变为200*200的文件;
             .write("./img/meinv2.jpg",function (err) {
                 if(err){
                     res.send({"bok":false,"msg":err});
                 }else{
                     res.send({"bok":true,"msg":"截图成功"})
                 }
             })
        

2 扒网站,实现截图效果

  • 前端开发仓库
  • node.js实现切图;
    • 思路:
      • 发送get请求"/index",渲染页面;
      • 给按钮添加点击事件,在事件触发后,通过ajax发送get请求,将数据传到服务器;
      • 获取原代码中的截图元素,获取其宽高和定位left,top值;作为切图的数值;
      • 服务器拿到数据,通过gm模块进行裁切原图;然后保存;
      • 裁切成功后,响应给页面,通过ajax中success拿到数据,弹出提示,刷新页面;
    • 注意:
      • 必须在点击事件中,获取元素,拿到数据;不能再点击事件外拿,否则,拿到的数据均为0;
      • 如果图片在页面中被缩放,需要拿到比例,传给服务器,因为,服务器是在原图上裁切的;
    • 知识点:
      • 如果一个元素设置定位,在jQuery中通过$("xx").position().left$("xx").position().top来获取left和top值;
    • 代码:
      • ejs中自己写的script代码:
       <script>
           //必须在点击事件触发后,在获取元素拿值,否则,无法拿到值;
           $("#btn").click(function () {
               var $img=$("#target");
               var imgw=$img.width();
               var bl=1366/imgw;//获取到一个比例;
               var $div=$(".jcrop-holder>div:eq(0)");
               var w=$div.width()*bl;
               var h=$div.height()*bl;
               var l=$div.position().left*bl;
               var t=$div.position().top*bl;
               $.ajax({
                   url:"/jietu",
                   type:"get",
                   data:{w,h,l,t},
                   success:function (val) {
                       if(val.bok){
                           alert(val.msg);
                           window.location.href="/index";//更新页面;
                       }else{
                           console.log(val.msg);
                       }
                   }
               })
           })
       </script>
      
      • 服务器代码:
       const express=require("express");
       const fs=require("fs");
       const gm=require("gm");
       const app=express();
       app.listen(8080);
       
       //设置ejs模板引擎
       app.set("view engine","ejs");
       //设置静态资源目录
       app.use(express.static("./public"));//此静态资源是为了引入css和js等;
       //设置静态资源目录
       app.use(express.static("./img"));//此静态资源是为了引入图片;
       
       //发送请求渲染页面;
       app.get("/index",function (req, res) {
           res.render("index");
       });
       //ajax发送请求,截图
       app.get("/jietu",function (req, res) {
           //获取到参数值
           var {w,h,l,t}=req.query;
           //切图
           gm("./img/meinv.jpg")
               .crop(w,h,l,t)
               .write("./img/meinv2.jpg",function (err) {
                   if(err){
                       res.send({"bok":false,"msg":err});
                   }else{
                       res.send({"bok":true,"msg":"截图成功"})
                   }
               })
       });
      

3 封装后的裁图文件

  • 封装后的文件
    • 文件存储github地址:cutImg
    • 服务器cutapp.js
     //1.express三步创建服务器基本构架
     const express=require("express");
     const app=express();
     app.listen(3333,function () {
         console.log("3333 server is running");
     });
     //2.引入node系统模块
     const path=require("path");
     const fs=require("fs");
     //3.引入第三方模块
     const formidable=require("formidable");
     const sd=require("silly-datetime");
     const gm=require("gm");
     
     //4.设置ejs模板引擎
     app.set("view engine","ejs");
     
     //5.设置静态资源目录
     //1)加载ejs文件中的css,js等静态资源
     app.use("/public",express.static("./public"));
     //2)加载uploads文件夹中上传的图片
     app.use("/uploads",express.static("./uploads"));
     //3)加载avatar文件夹上的裁切后的图片
     app.use("/avatar",express.static("./avatar"));
     
     //6.设置路由
     //1)加载上传文件目录
     app.get('/tofile',function (req, res, next) {
         res.render('tofile',{});
     });
     //2)提交上传文件数据
     app.post('/todata',function (req, res, next) {
         //新建form对象
         var form=new formidable.IncomingForm();
         //设置文件上传路径
         form.uploadDir="./uploads/";
         //解析上传的文件参数
         form.parse(req,function (err, fields, files) {
             if(err){
                 console.log('formidble错误');
                 return;
             }
             var oldPath=files.myfile.path;
             var originName=files.myfile.name;
             var originNameObj=path.parse(originName);
             var newName="gms"+sd.format(new Date(),"YYYYMMDD_HHmmss")+originNameObj.ext;
             var newPath=form.uploadDir+newName;
             //更换上传的文件路径和名字
             fs.rename(oldPath,newPath,function (err) {
                 if(err){
                     console.log('图片重命名失败');
                     return;
                 }
                 res.send({'bok':true,'msg':'上传图片成功!!!','imgsrc':newName});
             });
         })
     });
     //3)渲染裁切图页面
     app.get('/showcutimg',function (req, res, next) {
         var cutimgSrc=req.query.cursrc;
         res.render('mycut',{
             imgsrc:cutimgSrc
         })
     });
     //4)裁切图片
     app.get('/cutimg',function (req, res, next) {
         var curobj=req.query;
         gm("./uploads/"+curobj.imgsrc)
             .crop(curobj.w,curobj.h,curobj.x,curobj.y)
             .resize(curobj.xsize,curobj.ysize,"!")
             .write("./avatar/"+curobj.imgsrc,function (err) {
                 if(err){
                     res.send({"bok":false,"msg":err});
                 }else{
                     res.send({"bok":true,"msg":"截图成功"})
                 }
             });
     });
    
    • 上传页面tofile.ejs
     <!DOCTYPE html>
     <html lang="zh-CN">
     <head>
         <meta charset="utf-8">
         <meta http-equiv="X-UA-Compatible" content="IE=edge">
         <meta name="viewport" content="width=device-width, initial-scale=1">
         <!-- 上述3个meta标签*必须*放在最前面,任何其他内容都*必须*跟随其后! -->
         <title>文件上传页面</title>
     
         <!-- Bootstrap -->
         <link href="/public/vender/bootstrap/css/bootstrap.css" rel="stylesheet">
     
         <!-- HTML5 shim 和 Respond.js 是为了让 IE8 支持 HTML5 元素和媒体查询(media queries)功能 -->
         <!-- 警告:通过 file:// 协议(就是直接将 html 页面拖拽到浏览器中)访问页面时 Respond.js 不起作用 -->
         <!--[if lt IE 9]>
         <script src="https://cdn.jsdelivr.net/npm/html5shiv@3.7.3/dist/html5shiv.min.js"></script>
         <script src="https://cdn.jsdelivr.net/npm/respond.js@1.4.2/dest/respond.min.js"></script>
         <![endif]-->
     </head>
     <body>
     <div class="container files">
         <div class="row">
             <form class="form-horizontal col-xs-4 col-xs-offset-4">
                 <div class="form-group">
                     <h1 style="margin-top: 150px">请上传图像</h1>
                     <label for="myimg">上传文件</label>
                     <input type="file" id="myimg" name="myfile">
                     <div class="checkbox">
                         <label>
                             <input type="checkbox"> Check me out
                         </label>
                     </div>
                     <button type="button" class="btn btn-primary" id="toBtn">上传</button>
                 </div>
             </form>
         </div>
     </div>
     
     <!-- jQuery (Bootstrap 的所有 JavaScript 插件都依赖 jQuery,所以必须放在前边) -->
     <script src="/public/vender/jquery/jquery.js"></script>
     <!-- 加载 Bootstrap 的所有 JavaScript 插件。你也可以根据需要只加载单个插件。 -->
     <script src="/public/vender/bootstrap/js/bootstrap.js"></script>
     <script>
         //通过ajax上传file文件信息
         $('#toBtn').on('click',function () {
             //获取form表单的数据
             var formData=new FormData();
             formData.append('myfile',$('#myimg')[0].files[0])
             //ajax发送请求
             $.ajax({
                 url: '/todata',
                 type: 'POST',
                 data:formData,
                 dataType: 'json',
                 contentType: false,//不需要头;
                 processData: false,//不转换数据
                 success: function (data) {
                     alert(data.msg);
                     window.location.href='/showcutimg?cursrc='+data.imgsrc;
                 },
                 error: function (err) {
                     console.log(err);
                 }
             })
         })
     </script>
     </body>
     </html>
    
    • 裁切页面cutimg.ejs
     <!DOCTYPE html>
     <html lang="en">
     <head>
         <title>截图页面</title>
         <meta http-equiv="Content-type" content="text/html;charset=UTF-8" />
         <script src="/public/js/jquery.min.js"></script>
         <script src="/public/js/jquery.Jcrop.js"></script>
         <script src="/public/js/jquery-cut.js"></script>
         <script src="/public/js/mycut.js"></script>
         <link rel="stylesheet" href="/public/css/main.css" type="text/css" />
         <link rel="stylesheet" href="/public/css/demos.css" type="text/css" />
         <link rel="stylesheet" href="/public/css/jquery.Jcrop.css" type="text/css" />
         <link rel="stylesheet" href="/public/css/jquery-cut.css" type="text/css" />
         <link rel="stylesheet" href="/public/css/mycut.css" type="text/css" />
         <style rel="stylesheet" type="text/css">
             #preview-pane .preview-container{
                 width: 200px;
                 height: 200px;
             }
             .jcrop-holder #preview-pane{
                 top: 30%;
                 right: -300px;
             }
         </style>
     </head>
     <body>
     <div class="container">
         <div class="row">
             <div class="span12">
                 <div class="jc-demo-box">
                     <img src="/uploads/<%= imgsrc%>" data-imgsrc="<%= imgsrc%>" id="target" alt="cuttu" />
                     <div id="preview-pane">
                         <div class="preview-container">
                             <img src="/uploads/<%= imgsrc%>" class="jcrop-preview" alt="Preview" />
                         </div>
                     </div>
                     <div class="description">
                         <button id="btn">提交截图</button>
                     </div>
                     <div class="clearfix"></div>
                 </div>
             </div>
         </div>
     </div>
     </body>
     <script>
         //必须先声明
         var curobj;
         $("#btn").click(function () {
             curobj.imgsrc=$("#target").data("imgsrc");
             $.ajax({
                 url:"/cutimg",
                 type:"get",
                 data:curobj,
                 dataType: "json",
                 success:function (val) {
                     if(val.bok){
                         alert(val.msg);
                         window.location.href="/tofile";//裁切成功后,跳转回上传文件页面
                     }else{
                         console.log(val.msg);
                     }
                 },
                 error:function (err) {
                     console.log(err);
                 }
             })
         });
     </script>
     </html>
    
    • 项目介绍
     1.项目介绍:完成图片上传到裁切的功能;
     2.项目依赖
       express gm ejs formidable silly-datetime
     3.项目运行
       1)下载node,运行cutapp.js服务器
       2)网页地址:http://localhost:3333/tofile  加载上传文件页面
     4.目录分析
       uploads: 图片上传后的地址
       avatar: 图片裁切后,保存的地址
    

4 知识点

  • gm的一些命令
    • 显示图像文件详细信息:gm identify a.jpg;
    • 格式转换:gm convert a.jpg a.png;
    • 注意:必须在图片的目录下;运行命令;
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,236评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,867评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,715评论 0 340
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,899评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,895评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,733评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,085评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,722评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,025评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,696评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,816评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,447评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,057评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,009评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,254评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,204评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,561评论 2 343