微信小程序+七牛云水印功能 实现自定义图片分享

需求说明 :

一个社交 小程序,用户发表动态之后,要求实现点击分享按钮,根据动态内容 生成图片并自定义分享。如果 动态是 文字的话,需要将动态文字 和 ui 给定的背景图 合并生成新的图片,如果动态有图片的情况,需要 将动态第一张图,和ui 给定的背景 合并生成新的图片,替换 onShareAppMessage return 方法中 imageUrl字段。

WechatIMG206.jpeg

WechatIMG204.jpeg

WechatIMG203.jpeg

踩坑 :

小程序页面分享很容易实现,只需要在 onShareAppMessagereturn自定义 分享内容就好了,但是如果使用 button 按钮 的 开放能力open-type:share去自定义分享,就会出现问题:button按钮的share 能力,点击button 立即调起 好友列表,并同时触发 onShareAppMessage方法,且事件不可控,无法做延迟操作。也就是说 无法!先本地生成图片,然后替换 自定义图片地址!并且,如果在本地点一个 分享 就生成一个分享图 ,canvas绘制性能太慢,大大影响体验。

寻找实现方式:

首先想到的是,在 发表 动态的时候,本地生成分享图,然后 在发表动态接口传给后端,然后前端在 点击 share button 的时候 直接 拿后端 shareimg 地址 替换 onShareAppMessageimgUrl字段。这样都是同步操作,便可以实现 不同动态,不同的分享图片。但是经过后端交涉,认为这种方案,白白浪费服务器资源,每次都生成一个无用的分享图。不值得。

于是,我就去 找业内 别人的实现方式。 我找的 小打卡小程序。当我用charles 抓包他们点击动态分享时候请求的数据,看到了一个 分享图链接 如下 :

WechatIMG302.png

分享图链接:
http://img-union-cdn.sharedaka.com/noteshare/txt_bg_0.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s=,size_28,text_5omT5Y2h56ys5Zub5aSpICAgIDnmnIgxOOaXpSAg,color_FFFFFF,shadow_0,t_100,g_nw,x_42,y_62/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s=,size_28,text_6ZuoCgrpmIXor7vkuabnsY3vvJrjgIrpnZ7mmrTlipvmsp8=,color_FFFFFF,shadow_0,t_100,g_nw,x_42,y_106/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s=,size_28,text_6YCa44CLCgrnq6DoioLvvJrnrKzkuInnq6DigJzljLrliIY=,color_FFFFFF,shadow_0,t_100,g_nw,x_42,y_150/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s=,size_28,text_6KeC5a-f5ZKM6K-E6K664oCdCgrmkZjlvZXvvJrpnZ7mmrQ=,color_FFFFFF,shadow_0,t_100,g_nw,x_42,y_194/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s=,size_28,text_5Yqb5rKf6YCa55qE56ys5LiA5Liq6KaB57Sg5piv6KeCLi4u,color_FFFFFF,shadow_0,t_100,g_nw,x_28,y_238
于是我看到http://img-union-cdn.sharedaka.com/noteshare/txt_bg_0.png后面 跟着 一大堆参数,x-oss-process=image/watermark 原来是图片水印。

于是 我就找到了七牛云 生成水印的地方---图片处理 https://portal.qiniu.com/dora/fop/imageprocess

image.png

实现:

  1. 将图片背景图 上传至七牛云
  2. 用可视化编辑器 将 文字 作为水印合成到图片上
  3. 图片同理
    技术文档:https://developer.qiniu.com/dora/api/1316/image-watermarking-processing-watermark
    4 、注意 文字 需要 base64 转码并替换 + /
    image.png

实现代码 :


  onShareAppMessage: function (res) {
    if (res.from == 'button') {


      let noteImg = res.target.dataset.noteimg
      let notetext = res.target.dataset.notetext
      let shareImgUrl = ''


      if ((noteImg.length > 0 && notetext) || (notetext && noteImg.length == 0)) {
        // 没有图的情况
        console.log(notetext)
        shareImgUrl = base64Until.dealShareText(notetext)
      } else {
        // 有图的情况
        shareImgUrl = base64Until.dealShareImg(noteImg[0].imgPath)
      }

     let shareUrl = `pages/homework/homeworkShare?taskId=${res.target.dataset.taskid}&courseid=${res.target.dataset.courseid}&campClassStudentId=${this.data.indexData.campClassStudentId}`
 
      return {
        title: `${res.target.dataset.taskname}的作业` || '训练营主页',
        path: shareUrl,
        imageUrl: shareImgUrl || ''
      }
    } 

  },

/*
  *  base64编码(编码,配合encodeURIComponent使用)
  *  @parm : str 传入的字符串
  *  使用:
        1、引入util.js(路径更改) :const util  = require('../../utils/util.js');
        2、util.base64_encode(util.utf16to8('base64 编码'));
 */
function base64_encode(str) {
  //下面是64个基本的编码
  var base64EncodeChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
  var out, i, len;
  var c1, c2, c3;
  len = str.length;
  i = 0;
  out = "";
  while (i < len) {
    c1 = str.charCodeAt(i++) & 0xff;
    if (i == len) {
      out += base64EncodeChars.charAt(c1 >> 2);
      out += base64EncodeChars.charAt((c1 & 0x3) << 4);
      out += "==";
      break;
    }
    c2 = str.charCodeAt(i++);
    if (i == len) {
      out += base64EncodeChars.charAt(c1 >> 2);
      out += base64EncodeChars.charAt(((c1 & 0x3) << 4) | ((c2 & 0xF0) >> 4));
      out += base64EncodeChars.charAt((c2 & 0xF) << 2);
      out += "=";
      break;
    }
    c3 = str.charCodeAt(i++);
    out += base64EncodeChars.charAt(c1 >> 2);
    out += base64EncodeChars.charAt(((c1 & 0x3) << 4) | ((c2 & 0xF0) >> 4));
    out += base64EncodeChars.charAt(((c2 & 0xF) << 2) | ((c3 & 0xC0) >> 6));
    out += base64EncodeChars.charAt(c3 & 0x3F);
  }
  return out;
}
/*
  *  base64编码(编码,配合encodeURIComponent使用)
  *  @parm : str 传入的字符串
 */
function utf16to8(str) {
  var out, i, len, c;
  out = "";
  len = str.length;
  for (i = 0; i < len; i++) {
    c = str.charCodeAt(i);
    if ((c >= 0x0001) && (c <= 0x007F)) {
      out += str.charAt(i);
    } else if (c > 0x07FF) {
      out += String.fromCharCode(0xE0 | ((c >> 12) & 0x0F));
      out += String.fromCharCode(0x80 | ((c >> 6) & 0x3F));
      out += String.fromCharCode(0x80 | ((c >> 0) & 0x3F));
    } else {
      out += String.fromCharCode(0xC0 | ((c >> 6) & 0x1F));
      out += String.fromCharCode(0x80 | ((c >> 0) & 0x3F));
    }
  }
  return out;
}

/*
  *  base64解码(配合decodeURIComponent使用)
  *  @parm : input 传入的字符串
  *  使用:
        1、引入util.js(路径更改) :const util  = require('../../utils/util.js');
        2、util.base64_decode('YmFzZTY0IOe8lueggQ==');
 */
function base64_decode(input) {
  var base64EncodeChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
  var output = "";
  var chr1, chr2, chr3;
  var enc1, enc2, enc3, enc4;
  var i = 0;
  input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
  while (i < input.length) {
    enc1 = base64EncodeChars.indexOf(input.charAt(i++));
    enc2 = base64EncodeChars.indexOf(input.charAt(i++));
    enc3 = base64EncodeChars.indexOf(input.charAt(i++));
    enc4 = base64EncodeChars.indexOf(input.charAt(i++));
    chr1 = (enc1 << 2) | (enc2 >> 4);
    chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
    chr3 = ((enc3 & 3) << 6) | enc4;
    output = output + String.fromCharCode(chr1);
    if (enc3 != 64) {
      output = output + String.fromCharCode(chr2);
    }
    if (enc4 != 64) {
      output = output + String.fromCharCode(chr3);
    }
  }
  return utf8_decode(output);
}

/*
  *  utf-8解码
  *  @parm : utftext 传入的字符串
 */
function utf8_decode(utftext) {
  var string = '';
  let i = 0;
  let c = 0;
  let c1 = 0;
  let c2 = 0;
  while (i < utftext.length) {
    c = utftext.charCodeAt(i);
    if (c < 128) {
      string += String.fromCharCode(c);
      i++;
    } else if ((c > 191) && (c < 224)) {
      c1 = utftext.charCodeAt(i + 1);
      string += String.fromCharCode(((c & 31) << 6) | (c1 & 63));
      i += 2;
    } else {
      c1 = utftext.charCodeAt(i + 1);
      c2 = utftext.charCodeAt(i + 2);
      string += String.fromCharCode(((c & 15) << 12) | ((c1 & 63) << 6) | (c2 & 63));
      i += 3;
    }
  }
  return string;
}

/*
    * base64编码函数封装
    * @parm: str(传入要编成base64的内容)
    * 使用:
        1、引入util.js(路径更改) :const util  = require('../../utils/util.js');
        2、util.baseEncode('base64 编码');
*/
function baseEncode(str) {
  return base64_encode(utf16to8(str));
}



function dealShareText(text){
  // 先看一下 text 的长度,如果大于 30 返回  三段  ,
  console.log(text)
  let length = text.length
  let str1 = ''
  let str2 = ''
  let str3 = ''
  let  url = ''
  console.log(length)
  let baseUrl = 'http://img.yi-chuangxin.com/Fn64f5WddnKWXTy5tu1kCdCmcAan?imageView2/1/w/500/h/400/q/100'
  if(length>30){
    let str = text.substr(0,27)+'...'
    str1  = str.substr(0,10)
    str2 = str.substr(10,10)
    str3 = str.substr(20,10)
    str1 = baseEncode(str1).replace(/\+/g,'-').replace(/\//g,'_')
    str2 = baseEncode(str2).replace(/\+/g,'-').replace(/\//g,'_')
    str3 = baseEncode(str3).replace(/\+/g,'-').replace(/\//g,'_')
     url  = `${baseUrl}|watermark/2/text/${str1}/font/6buR5L2T/fontsize/600/fill/IzE4M0Y4Qg==/dissolve/100/gravity/North/dx/10/dy/100|watermark/2/text/${str2}/font/6buR5L2T/fontsize/600/fill/IzE4M0Y4Qg==/dissolve/100/gravity/North/dx/10/dy/160|watermark/2/text/${str3}/font/6buR5L2T/fontsize/600/fill/IzE4M0Y4Qg==/dissolve/100/gravity/North/dx/10/dy/220`
  }else if(length>20&&length<=30){
    str1  = text.substr(0,10)
    str2 = text.substr(10,10)
    str3 = text.substr(20,10)
     url  = `${baseUrl}|watermark/2/text/${baseEncode(str1).replace(/\+/g,'-').replace(/\//g,'_')}/font/6buR5L2T/fontsize/600/fill/IzE4M0Y4Qg==/dissolve/100/gravity/North/dx/10/dy/100|watermark/2/text/${baseEncode(str2).replace(/\+/g,'-').replace(/\//g,'_')}/font/6buR5L2T/fontsize/600/fill/IzE4M0Y4Qg==/dissolve/100/gravity/North/dx/10/dy/160|watermark/2/text/${baseEncode(str3).replace(/\+/g,'-').replace(/\//g,'_')}/font/6buR5L2T/fontsize/600/fill/IzE4M0Y4Qg==/dissolve/100/gravity/North/dx/10/dy/220`
  }else if(length>10&&length<=20){
    str1  = text.substr(0,10)
    str2 = text.substr(10,10)
    url  = `${baseUrl}|watermark/2/text/${baseEncode(str1).replace(/\+/g,'-').replace(/\//g,'_')}/font/6buR5L2T/fontsize/600/fill/IzE4M0Y4Qg==/dissolve/100/gravity/North/dx/10/dy/100|watermark/2/text/${baseEncode(str2).replace(/\+/g,'-').replace(/\//g,'_')}/font/6buR5L2T/fontsize/600/fill/IzE4M0Y4Qg==/dissolve/100/gravity/North/dx/10/dy/160`
  }else if(length<=10){
    str1  = text.substr(0,10)
    url  = `${baseUrl}|watermark/2/text/${baseEncode(str1).replace(/\+/g,'-').replace(/\//g,'_')}/font/6buR5L2T/fontsize/600/fill/IzE4M0Y4Qg==/dissolve/100/gravity/North/dx/10/dy/100`
  }

  return url 

}

function dealShareImg(imgUrl){
  let imgurl = `${imgUrl}?imageView2/1/w/460/h/364/q/75`

  let baseUrl = 'http://img.yi-chuangxin.com/Fihxh0GqlfTrWC45qfGP9Z_lT5U0?imageView2/1/w/500/h/400/q/75'
  let url = `${baseUrl}|watermark/1/image/${baseEncode(imgurl).replace(/\+/g,'-').replace(/\//g,'_')}/dissolve/100/gravity/Center/dx/10/dy/10`

  return url
}



/*
    * base64解码函数封装
    * @parm: str(传入要解为正常字体)
    * 使用:
        1、引入util.js(路径更改) :const util  = require('../../utils/util.js');
        2、util.baseDecode(util.baseEncode('base64 编码'))
*/
function baseDecode(str) {
  return base64_decode(str);
}// 抛出函数使用
module.exports = {
  baseEncode: baseEncode,
  baseDecode: baseDecode,
  dealShareText:dealShareText,
  dealShareImg:dealShareImg
}

总结:
用同样的方法 ,可以生产任何海报内容,无需canvas 生成,生成速度快,不占用服务器资源

你可能感兴趣的:(微信小程序+七牛云水印功能 实现自定义图片分享)