Node.js——微信聊天圖片發(fā)送功能實(shí)現(xiàn)

圖片實(shí)現(xiàn)功能分瀏覽器實(shí)現(xiàn)

這次主要要寫如何通過右鍵粘貼獲得截圖(沒錯(cuò),就是QQ截圖)以及網(wǎng)絡(luò)圖片

chrome

$("body").on('paste','.emoji-wysiwyg-editor',function(event){

        var clipboardData = (event.clipboardData || event.originalEvent.clipboardData);
        //chrome提供了直接獲取剪切板上內(nèi)容的API,有的chrome瀏覽器是event.clipboardData,有的則是event.originalEvent.clipboardData
        if ( clipboardData.items ) {
            var  items = clipboardData.items,
                len = items.length,
            //如果粘貼純文本,那么len=1,如果粘貼網(wǎng)頁圖片,len=2, items[0].type = 'text/plain', items[1].type = 'image/*'
            //如果使用截圖工具粘貼圖片铭污,len=1, items[0].type = 'image/png'
                blob = null;

            for (var i = 0; i < len; i++) {
                console.log(items[i]);
                console.log( items[i].type);
                if (items[i].type.indexOf("image") !== -1) {
                    event.preventDefault();
                    blob = items[i].getAsFile();
                    //blob就是需要上傳到服務(wù)器的內(nèi)容
                }
            }
            console.log(blob);
            if ( blob !== null ) {
                var reader = new FileReader();
                reader.onload = function (event) {
                //文件讀取成功完成時(shí)觸發(fā)
                    // event.target.result 即為圖片的Base64編碼字符串
                    var base64_str = event.target.result;
                    //console.log(base64_str);
                    //根據(jù)后端服務(wù)器來選擇上傳base64的編碼或者直接上傳blob對象
                    doUpload(blob);
                }
                reader.readAsDataURL(blob);
                //該方法將文件讀取為一段以 data: 開頭的字符串株婴,這段字符串的實(shí)質(zhì)就是 Data URL肯腕,Data URL是一種將小文件直接嵌入文檔的方案朗涩。這里的小文件通常是指圖像與 html 等格式的文件取视。
            }
       }

})


//ajax

function doUpload(file) {

    $(".pg-wrapper").show();

    var file = file;
    //獲取img的后綴,png鬼雀、jpg等
    console.log(file.type);
    var form = new FormData();
    form.append("file", file);
    form.append("filetype",file.type);
    console.log(form);

    $.ajax({
        url: "/uploadImg",
        type: "POST",
        data: form,
        async: true,
        processData: false,
        contentType: false,
        success: function(result) {
            $.Insertimage(result.data);
            //圖片上傳到服務(wù)器后臺(tái)成功后返回圖片的地址,Insetimage用于插入圖片
        }
    });
        //$.Insertimage補(bǔ)充于jquery-emojirea.js這個(gè)閉包函數(shù)中
        $.Insertimage= function (url) {
        if (CONST.hasFocus) {
            CONST.selection = util.saveSelection();
                        //CONST指向EmojiArea_WYSIWYG(上一篇文章提過,這個(gè)函數(shù)寫在jquery-emojirea.js這個(gè)閉包函數(shù)中)
                        //如果文本編輯框div被處于focus狀態(tài),則調(diào)用 util.saveSelection()函數(shù)獲取當(dāng)前光標(biāo)對象并復(fù)制給CONST.selection
        }
        var $img = $(EmojiArea.createImage(url));
                //將url包裝成為<img src=url>的格式
        if ($img[0].attachEvent) {
            $img[0].attachEvent('onresizestart', function(e) { e.returnValue = false; }, false);
        }
        console.dir(CONST.$editor+"這里是const");
        CONST.$editor.trigger('focus');
        if (CONST.selection) {
            util.restoreSelection(CONST.selection);
                        //將文本編輯框的selection(也可以是歷史記錄)存入util中,設(shè)置當(dāng)前selection為CONST.selection
        }
        try { util.replaceSelection($img[0]); } catch (e) {}
                //對光標(biāo)部分進(jìn)行替換
        CONST.onChange();
                //onChange方法用于將div的內(nèi)容賦值給對應(yīng)的textarea中
    }

}

對應(yīng)后臺(tái)程序

后臺(tái)用的是Node.js以及express

var formidable = require('formidable');
var fs = require('fs');
router.post('/uploadImg', function(req, res, next) {

  var io = global.io;
//var io = require('socket.io').listen(server);global.io = io;,io是全局變量

  var form = new formidable.IncomingForm();
  var path = "";
  var fields = [];

  form.encoding = 'utf-8';
  form.uploadDir = "upload";
  form.keepExtensions = true;
  form.maxFieldsSize = 30000 * 1024 * 1024;


  var uploadprogress = 0;
  //console.log("start:upload----"+uploadprogress);

  form.parse(req);

  form.on('field', function(field, value) {
    fields[field] = value;
    //主要用于存儲(chǔ)filetype
  })
      .on('file', function(field, file) {
        path = '\\' + file.path;
        if(fields['filetype'].match(/image/)){
          var str = fields['filetype'].match(/[^image\/]\w+$/);//提取image/后面部分的圖片后綴
          var str = str[0];
          var reg = new RegExp(str);
          if(!file.path.match(reg)){
          //如果file的路徑不含圖片后綴則執(zhí)行以下操作
            fs.rename(file.path,file.path+'.'+str, function(err){
              if(err){
                throw err;
              }
              console.log('done!');
              path = '\\' + file.path+'.'+str;
            })
          }else{
            path = '\\' + file.path;
          }
        }else{
          path = '\\' + file.path;
        }



      })
      .on('progress', function(bytesReceived, bytesExpected) {

        uploadprogress = (bytesReceived / bytesExpected * 100).toFixed(0);
        //console.log("upload----"+ uploadprogress);
        io.sockets.in('sessionId').emit('uploadProgress', uploadprogress);
      })
      .on('end', function() {

        //console.log('-> upload done\n');
        entries.code = 0;

        if(fields['filetype'].match(/image/)){
          var str = fields['filetype'].match(/[^image\/]\w+$/);
          var str = str[0];
          var reg = new RegExp(str);
          if(!path.match(reg)){
            path = path + '.' + str;
          }
        }//再次檢查path是否正確(其實(shí)上面一段檢查并沒有什么卵用)


        entries.data = path;
        res.writeHead(200, {
          'content-type': 'text/json'
        });
        res.end(JSON.stringify(entries));//將圖片地址作為json數(shù)據(jù)傳送到前臺(tái)
      })
      .on("err",function(err){
        var callback="<script>alert('"+err+"');</script>";
        res.end(callback);//這段文本發(fā)回前端就會(huì)被同名的函數(shù)執(zhí)行
      }).on("abort",function(){
    var callback="<script>alert('"+ttt+"');</script>";
    res.end(callback);
  });

});

firefox

$("body").on('paste','.emoji-wysiwyg-editor',function(event){
           setTimeout(function () {
                //設(shè)置setTimeout的原因是為了保證圖片先插入到div里乔遮,然后去獲取值
                $(".emoji-wysiwyg-editor img").each(function () {
                    if($(this).attr("src").toString().match(/base64/)){//火狐瀏覽器不提供獲取clipboard內(nèi)容的api,但是允許粘貼圖片到可編輯的div中,粘貼后的圖片的src是base64編碼的形式,可將其上傳到服務(wù)器
                        var base64_str = $(this).attr("src");
                        doUploadFF(base64_str);
                    }else if($(this).attr("alt")===undefined||!$(this).attr("alt").toString().match(/^:.+:$/))
                    {
                        var base64_str = $(this).attr("src");
                        doUploadFF(base64_str);
                    }
                    //兩個(gè)if語句第一個(gè)用于獲取截圖的到的本地圖片,第二個(gè)用于獲取網(wǎng)頁上的圖片復(fù)制過來的,貌似沒差
                })
            }, 1);
})
//ajax
function doUploadFF(base64_str) {

    console.log(base64_str);

    $.ajax({
        url: "/uploadImgFF",
        type: "POST",
        data:JSON.stringify({
            'base64':base64_str,
        }),
        async: true,
        processData: false,
        contentType:"application/json",
        success: function(result) {
            console.log(result.store_path);
            //$.Insetimage(result.data);
            $(".emoji-wysiwyg-editor img").each(function () {
                if($(this).attr("src").toString().match(/base64/)){
                    $(this).attr({src:result.store_path,alt:":"+result.store_path+":"});
                    $(this).addClass("Notemoji");
                    $.constChange();
                }else if($(this).attr("alt")===undefined||!$(this).attr("alt").toString().match(/^:.+:$/))
                {
                    $(this).attr({src:result.store_path,alt:":"+result.store_path+":"});
                    $(this).addClass("Notemoji");
                    $.constChange();
                }
            })
        }
    });
}

后臺(tái)

router.post('/uploadImgFF',function (req,res,next) {
  //1.獲取客戶端傳來的src_str字符串=>判斷是base64還是普通地址=>獲取圖片類型后綴(jpg/png etc)
//=>如果是base64替換掉"前綴"("data:image\/png;base64," etc)
//2.base64 轉(zhuǎn)為 buffer對象 普通地址則先down下來
//3.寫入硬盤(后續(xù)可以將地址存入數(shù)據(jù)庫)
//4.返回picture地址

  var src_str = req.body.base64,
      timestamp = new Date().getTime();
  console.log(src_str);

  if ( src_str.match(/^data:image\/png;base64,|^data:image\/jpg;base64,|^data:image\/jpg;base64,|^data:image\/bmp;base64,/) ) {
    //處理截圖 src_str為base64字符串

    var pic_suffix = src_str.split(';',1)[0].split('/',2)[1],
        base64 = src_str.replace(/^data:image\/png;base64,|^data:image\/jpg;base64,|^data:image\/jpg;base64,|^data:image\/bmp;base64,/, ''),
        buf = new Buffer(base64, 'base64'),
        store_path = './upload/' + timestamp + '.' + pic_suffix;
        console.log(store_path);

    fs.writeFile(store_path, buf, function (err) {
      if (err) {
        throw err;
      } else {
        res.json({'store_path': store_path});
      }
  });
} else {
  console.log("網(wǎng)頁圖片"+src_str);
  var temp_array = src_str.split('.'),
      pic_suffix = temp_array[temp_array.length - 1],
      store_path = './upload/' + timestamp + '.' + pic_suffix,
      wstream = fs.createWriteStream(store_path);
  console.log(store_path);
  request(src_str).pipe(wstream);
  wstream.on('finish', function (err) {
    console.log("進(jìn)入finish");
    if( err ) {
      throw err;
    } else {
      res.json({'store_path': store_path});
    }
  });


}
})
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市取刃,隨后出現(xiàn)的幾起案子蹋肮,更是在濱河造成了極大的恐慌,老刑警劉巖璧疗,帶你破解...
    沈念sama閱讀 216,324評(píng)論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件坯辩,死亡現(xiàn)場離奇詭異,居然都是意外死亡崩侠,警方通過查閱死者的電腦和手機(jī)漆魔,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,356評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來却音,“玉大人改抡,你說我怎么就攤上這事∠灯埃” “怎么了阿纤?”我有些...
    開封第一講書人閱讀 162,328評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長夷陋。 經(jīng)常有香客問我欠拾,道長,這世上最難降的妖魔是什么骗绕? 我笑而不...
    開封第一講書人閱讀 58,147評(píng)論 1 292
  • 正文 為了忘掉前任藐窄,我火速辦了婚禮,結(jié)果婚禮上酬土,老公的妹妹穿的比我還像新娘荆忍。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,160評(píng)論 6 388
  • 文/花漫 我一把揭開白布刹枉。 她就那樣靜靜地躺著践惑,像睡著了一般。 火紅的嫁衣襯著肌膚如雪嘶卧。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,115評(píng)論 1 296
  • 那天凉袱,我揣著相機(jī)與錄音芥吟,去河邊找鬼。 笑死专甩,一個(gè)胖子當(dāng)著我的面吹牛钟鸵,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播涤躲,決...
    沈念sama閱讀 40,025評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼棺耍,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了种樱?” 一聲冷哼從身側(cè)響起蒙袍,我...
    開封第一講書人閱讀 38,867評(píng)論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎嫩挤,沒想到半個(gè)月后害幅,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,307評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡岂昭,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,528評(píng)論 2 332
  • 正文 我和宋清朗相戀三年以现,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片约啊。...
    茶點(diǎn)故事閱讀 39,688評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡邑遏,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出恰矩,到底是詐尸還是另有隱情记盒,我是刑警寧澤,帶...
    沈念sama閱讀 35,409評(píng)論 5 343
  • 正文 年R本政府宣布外傅,位于F島的核電站孽鸡,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏栏豺。R本人自食惡果不足惜彬碱,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,001評(píng)論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望奥洼。 院中可真熱鬧巷疼,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,657評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至骡尽,卻和暖如春遣妥,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背攀细。 一陣腳步聲響...
    開封第一講書人閱讀 32,811評(píng)論 1 268
  • 我被黑心中介騙來泰國打工箫踩, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人谭贪。 一個(gè)月前我還...
    沈念sama閱讀 47,685評(píng)論 2 368
  • 正文 我出身青樓境钟,卻偏偏與公主長得像,于是被迫代替她去往敵國和親俭识。 傳聞我的和親對象是個(gè)殘疾皇子慨削,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,573評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,070評(píng)論 25 707
  • WebSocket-Swift Starscream的使用 WebSocket 是 HTML5 一種新的協(xié)議。它實(shí)...
    香橙柚子閱讀 23,848評(píng)論 8 183
  • 小時(shí)候套媚,在紅薯剛剛可以吃的時(shí)候缚态,我們就鬧騰著要吃。于是父母有時(shí)候上地里干活回來堤瘤,會(huì)扒上幾個(gè)拿回家猿规,給我們嘗鮮。其實(shí)...
    楓紅云天閱讀 904評(píng)論 20 14
  • 實(shí)現(xiàn)后臺(tái)自動(dòng)生成文檔宙橱,減少前后臺(tái)溝通成本姨俩。spring mvc與swagger的集成 1. 下載https://g...
    晨宇閱讀 1,544評(píng)論 2 2
  • 陳元達(dá)反對劉聰修建昭儀殿,他估計(jì)肯定要出事师郑,所以拿鎖把自己鎖起來环葵。這就是,有孚宝冕,血去惕出张遭,無咎。通過鎖起來搏一把地梨,...
    Nuckyli閱讀 180評(píng)論 0 0