需求说明 :
一个社交 小程序,用户发表动态之后,要求实现点击分享按钮,根据动态内容 生成图片并自定义分享
。如果 动态是 文字的话,需要将动态文字 和 ui 给定的背景图 合并生成新的图片,如果动态有图片的情况,需要 将动态第一张图,和ui 给定的背景 合并生成新的图片,替换 onShareAppMessage
return 方法中 imageUrl
字段。
WechatIMG204.jpeg
WechatIMG203.jpeg
踩坑 :
小程序页面分享很容易实现,只需要在 onShareAppMessage
中return
自定义 分享内容就好了,但是如果使用 button 按钮 的 开放能力open-type:share
去自定义分享,就会出现问题:button按钮的share 能力,点击button 立即调起 好友列表,并同时触发 onShareAppMessage
方法,且事件不可控,无法做延迟操作。也就是说 无法!先本地生成图片,然后替换 自定义图片地址!
并且,如果在本地点一个 分享 就生成一个分享图 ,canvas绘制性能太慢,大大影响体验。
寻找实现方式:
首先想到的是,在 发表 动态的时候,本地生成分享图,然后 在发表动态接口传给后端,然后前端在 点击 share button 的时候 直接 拿后端 shareimg 地址 替换 onShareAppMessage
的 imgUrl
字段。这样都是同步操作,便可以实现 不同动态,不同的分享图片。但是经过后端交涉,认为这种方案,白白浪费服务器资源,每次都生成一个无用的分享图。不值得。
于是,我就去 找业内 别人的实现方式。 我找的 小打卡
小程序。当我用charles 抓包他们点击动态分享时候请求的数据,看到了一个 分享图链接 如下 :
分享图链接:
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
实现:
- 将图片背景图 上传至七牛云
- 用可视化编辑器 将 文字 作为水印合成到图片上
- 图片同理
技术文档:https://developer.qiniu.com/dora/api/1316/image-watermarking-processing-watermark
4 、注意 文字 需要 base64 转码并替换 + /
image.png
实现代码 :
<button data-courseid="{{homeworkData.courseId}}" data-taskid="{{homeworkData.id}}" data-notetext="{{homeworkData.content}}" data-noteimg="{{homeworkData.imgList}}" data-taskname='{{homeworkData.wxNickName}}' open-type="share" hover-start-time="100" class="shareComment" plain="{{true}}" style="border:none">
<image class="shareIcon" src="./img/work_share.png"></image>
<text class="samllText">分享</text>
</button>
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 生成,生成速度快,不占用服务器资源
网友评论