前言:

  对于小程序大家可能都非常熟悉了,随着小程序的不断普及越来越多的公司都开始推广使用起来了。今天接到一个需求就是生成小程序码,并且于运营给的推广图片合并在一起做成一张漂亮美观的推广二维码,扫码这种二维码就可以进入小程序。为了节省服务器内存资源,我想的就是成功调用通微信生成小程序码的接口后直接把微信返回过来的图片二进制内容(返回的图片 Buffer)转化为二进制byte[]文件流,然后再转成Image这样就不需要在保存到本地直接读取本地的背景图片通过GDI+(Graphics)绘制图片。废话不多说直接上码,各位同学假如有什么小程序的开发问题都欢迎评论区,或者qq私聊我有时间都可以一起学习探索。

选择小程序码生成方式:

首先微信小程序官方文档提供了三种生成小程序码的方法,如下所示(本文采用的是第三种,需要的码数量极多的业务场景):

文档详情地址:https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/qr-code/wxacode.getUnlimited.html

1、createwxaqrcode获取小程序二维码,适用于需要的码数量较少的业务场景。通过该接口生成的小程序码,永久有效,有数量限制。

2、getwxacode获取小程序码,适用于需要的码数量较少的业务场景。通过该接口生成的小程序码,永久有效,有数量限制。

3、getwxacodeunlimit获取小程序码,适用于需要的码数量极多的业务场景。通过该接口生成的小程序码,永久有效,数量暂无限制。

获取小程序全局唯一后台接口调用凭据(access_token):

  对接开发过微信相关的业务的同学应该都清楚,调用微信接口很多情况下都会需要使用到access_token接口调用凭证。一般来说access_token的有效时长为2小时,为了不频繁调用该接口我们可以通过缓存的方法把调用凭证存起来并设置合理的过期时间(redis,cookie,memorycache都是非常不错的选择)。

请求地址:

GET https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET

请求参数:

属性 类型 默认值 必填 说明
grant_type string   填写 client_credential
appid string   小程序唯一凭证,即 AppID,可在「微信公众平台 - 设置 - 开发设置」页中获得。(需要已经成为开发者,且帐号没有异常状态)
secret string   小程序唯一凭证密钥,即 AppSecret,获取方式同 appid

返回值(JSON 数据包):

属性 类型 说明
access_token string 获取到的凭证
expires_in number 凭证有效时间,单位:秒。目前是7200秒之内的值。
errcode number 错误码
errmsg string 错误信息

请求代码:

  1. /// <summary>
  2. /// 获取小程序全局唯一后台接口调用凭据(access_token)
  3. /// </summary>
  4. /// <returns></returns>
  5. public string GetWechatAccessToken()
  6. {
  7. var appId = "你的小程序AppID";//小程序唯一凭证,即 AppID
  8. var secret = "你的小程序AppSecret"; //小程序唯一凭证密钥,即 AppSecret
  9. string Url = string.Format("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={0}&secret={1}", appId, secret);
  10.  
  11. string Result = HttpWebRequest(Url, "GET", "", Encoding.UTF8);
  12.  
  13. var obj = JsonConvert.DeserializeObject<AccessToken>(Result);
  14.  
  15. if (obj != null && obj.access_token != null)
  16. {
  17. return obj.access_token;
  18. }
  19. else
  20. {
  21. return "";
  22. }
  23. }
  24.  
  25. /// <summary>
  26. /// WebRequest网络请求
  27. /// </summary>
  28. /// <param name="requestUrl">请求地址</param>
  29. /// <param name="method">请求方式(GET/POST)</param>
  30. /// <param name="data">请求参数(method="POST"需要携带)</param>
  31. /// <param name="encoding">字符编码</param>
  32. /// <param name="contentType">请求数据的内容类型</param>
  33. /// <returns></returns>
  34. public string HttpWebRequest(string requestUrl, string method, string data, Encoding encoding,string contentType="application/json;charset=UTF-8")
  35. {
  36. WebRequest webRequest = WebRequest.Create(requestUrl);
  37. webRequest.Method = method;
  38. if (method == "POST")
  39. {
  40. byte[] bytes = Encoding.Default.GetBytes(data);
  41. webRequest.ContentType = contentType;
  42. webRequest.ContentLength = bytes.Length;
  43. Stream requestStream = webRequest.GetRequestStream();
  44. requestStream.Write(bytes, 0, bytes.Length);
  45. requestStream.Close();
  46. }
  47.  
  48. WebResponse response = webRequest.GetResponse();
  49. Stream responseStream = response.GetResponseStream();
  50. if (responseStream == null)
  51. {
  52. return "";
  53. }
  54.  
  55. StreamReader streamReader = new StreamReader(responseStream, encoding);
  56. string result = streamReader.ReadToEnd();
  57. responseStream.Close();
  58. streamReader.Close();
  59. return result;
  60. }
  61.  
  62. /// <summary>
  63. /// 响应模型
  64. /// </summary>
  65. public class AccessToken
  66. {
  67. /// <summary>
  68. /// 获取到的凭证
  69. /// </summary>
  70. public string access_token { get; set; }
  71.  
  72. /// <summary>
  73. /// 凭证有效时间,单位:秒。目前是7200秒之内的值
  74. /// </summary>
  75. public int expires_in { get; set; }
  76.  
  77. /// <summary>
  78. /// 错误码
  79. /// </summary>
  80. public int errcode { get; set; }
  81.  
  82. /// <summary>
  83. /// 错误信息
  84. /// </summary>
  85. public string errmsg { get; set; }
  86. }

小程序码获取:

请求地址:

  1. POST https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=ACCESS_TOKEN

请求参数

属性 类型 默认值 必填 说明
access_token string   接口调用凭证
scene string   最大32个可见字符,只支持数字,大小写英文以及部分特殊字符:!#$&'()*+,/:;=?@-._~,其它字符请自行编码为合法字符(因不支持%,中文无法使用 urlencode 处理,请使用其他编码方式)
page string 主页 必须是已经发布的小程序存在的页面(否则报错),例如 pages/index/index, 根路径前不要填加 /,不能携带参数(参数请放在scene字段里),如果不填写这个字段,默认跳主页面
width number 430 二维码的宽度,单位 px,最小 280px,最大 1280px
auto_color boolean false 自动配置线条颜色,如果颜色依然是黑色,则说明不建议配置主色调,默认 false
line_color Object {"r":0,"g":0,"b":0} auto_color 为 false 时生效,使用 rgb 设置颜色 例如 {"r":"xxx","g":"xxx","b":"xxx"} 十进制表示
is_hyaline boolean false 是否需要透明底色,为 true 时,生成透明底色的小程序

请求成功返回值:

返回的图片 Buffer(如果调用成功,会直接返回图片二进制内容(图片文件流),如果请求失败,会返回 JSON 格式的数据。)

请求异常返回值:

属性 类型 说明
errcode number 错误码
errmsg string 错误信息

请求代码:

注意:这个与前面获取授权凭证的网络请求不同的是因为要接收请求返回过来的图片二进制内容(buffer),然后需要把二进制文件流转化为byte[]二进制字节流,然后在转化Image。

  1. /// <summary>
  2. /// 获取小程序码图片
  3. /// </summary>
  4. /// <param name="access_token">接口调用凭据</param>
  5. /// <param name="param">携带参数</param>
  6. private Image GetWetchatAppletQRCodeImage(string access_token, string param)
  7. {
  8. string requestData = "{\"scene\":\"" + param + "\"}";
  9. string requestUrl = "https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=" + access_token;
  10.  
  11. HttpWebRequest request = (HttpWebRequest)WebRequest.Create(requestUrl);
  12. request.Method = "POST";
  13. request.ContentType = "application/json;charset=UTF-8";
  14. byte[] payload = System.Text.Encoding.UTF8.GetBytes(requestData);
  15. request.ContentLength = payload.Length;
  16. Stream writer = request.GetRequestStream();
  17. writer.Write(payload, 0, payload.Length);
  18. writer.Close();
  19. HttpWebResponse response;
  20. response = (HttpWebResponse)request.GetResponse();
  21. Stream stream = response.GetResponseStream();//获取返回的图片 Buffer(文件流)
  22. byte[] imageBuffer = StreamToBytes(stream);
  23.  
  24. return ByteArrayConvertToImage(imageBuffer);
  25. }
  26.  
  27. /// <summary>
  28. /// 将文件数据流转为二进制byte[]字节流
  29. /// </summary>
  30. /// <param name="stream">文件流</param>
  31. /// <returns></returns>
  32. private byte[] StreamToBytes(Stream stream)
  33. {
  34. List<byte> bytes = new List<byte>();
  35. int temp = stream.ReadByte();
  36. while (temp != -1)
  37. {
  38. bytes.Add((byte)temp);
  39. temp = stream.ReadByte();
  40. }
  41. return bytes.ToArray();
  42. }
  43.  
  44. /// <summary>
  45. /// byte [] 转化为Iamge
  46. /// </summary>
  47. /// <param name="buffer"></param>
  48. /// <returns></returns>
  49. public static Image ByteArrayConvertToImage(byte[] buffer)
  50. {
  51. using (MemoryStream ms = new MemoryStream(buffer))
  52. {
  53. // 直接调用Image库类中自带的方法使用MemoryStream实例对象获取Image
  54. return Image.FromStream(ms);
  55. }
  56. }

小程序码和背景图合并:

  1. /// <summary>
  2. /// 小程序推广二维码获取
  3. /// </summary>
  4. /// <param name="userId">小程序码携带的用户参数</param>
  5. /// <returns></returns>
  6. public JsonResult GetCompositePictureUrl(int userId)
  7. {
  8. //图片存放物理路径
  9. var savePhysicalPath = HttpContext.Request.MapPath("~/qrcode/");
  10.  
  11. var imgBack = Image.FromFile(savePhysicalPath + "ewm.jpg");//合成背景图片
  12. var wechatQrcodeImg = GetWetchatAppletQRCodeImage(GetWechatAccessToken(),userId.ToString());//获取小程序码图片
  13. var compositePictureUrl = CompositePicture(imgBack, wechatQrcodeImg, savePhysicalPath, 232, 719, 290, 290);
  14.  
  15. return Json(new { code = 0, compositePictureUrl = compositePictureUrl });
  16. }
  17.  
  18. /// <summary>
  19. /// 合成图片
  20. /// </summary>
  21. /// <param name="backgroundImage">背景图</param>
  22. /// <param name="qrCodeImg">二维码图片</param>
  23. /// <param name="savePhysicalPath">图片存放物理路径</param>
  24. /// <param name="xDeviation">绘制图像X轴偏差</param>
  25. /// <param name="yDeviation">绘制图像Y轴偏差</param>
  26. /// <param name="width">绘制图像宽</param>
  27. /// <param name="height">绘制图像高</param>
  28. /// <returns></returns>
  29. public string CompositePicture(Image backgroundImage, Image qrCodeImg, string savePhysicalPath, int xDeviation = 0, int yDeviation = 0, int width = 0, int height = 0)
  30. {
  31. Bitmap bitmap = new Bitmap(backgroundImage.Width, backgroundImage.Height);
  32. Graphics graphics = Graphics.FromImage(bitmap);//绘图
  33. graphics.Clear(Color.White);
  34. SolidBrush surush = new SolidBrush(Color.White);
  35. graphics.DrawImage(backgroundImage, 0, 0, backgroundImage.Width, backgroundImage.Height);
  36. graphics.DrawImage(qrCodeImg, xDeviation, yDeviation, width, height);
  37. GC.Collect();//垃圾清理
  38.  
  39. string compositePictureUrl = savePhysicalPath + Guid.NewGuid().ToString() + ".jpg";
  40. //合成图片保存
  41. bitmap.Save(compositePictureUrl, System.Drawing.Imaging.ImageFormat.Jpeg);
  42.  
  43. return compositePictureUrl;
  44. }

合成效果图:

.NET生成小程序码,并合自定义背景图生成推广小程序二维码的更多相关文章

  1. qrcodenet二维码图片下扩展区域添加号段的操作

    总监安排了个任务,一个号码导出一个二维码图, 我实现了最终还能批量生成,结果主管说要在图片下边添加一行,和图片是一起的 最开始把控件的上的图给改了,结果保存起来没用,控件上的图跟要保存的不是一个事. ...

  2. 一次CTF后对二维码的认识

    前一段时间参加一个CTF比赛的时候其中有一个题目就是一张二维码图片,然后获取其中的信息来解题,那个二维码的特别之处在于,它把3个位置探测区域用几张美女图片代替了,然后在做题的时候顺便简单的了解了一下二 ...

  3. uniapp 微信小程序 生成二维码

    使用 tki-qrcode组件 生成二维码(https://www.npmjs.com/package/tki-qrcode) 1.引入 tki-qrcode 下载组件后引入 import tkiQr ...

  4. 微信小程序与内嵌webview之间来回跳转的几点总结,以及二维码的使用

    截止到发稿小程序支持的功能,后续如果小程序更新在完善文稿. 1. 小程序可以内嵌组件跳转到h5页面,前提是在小程序后台配置相应的业务域名.新打开的h5页面会替代小程序组件内的其它组件,即为h5不能与小 ...

  5. 微信小程序二维码推广统计

    微信小程序可以通过生成带参数的二维码,那么这个参数是可以通过APP的页面进行监控的 这样就可以统计每个二维码的推广效果. 今天由好推二维码推出的小程序统计工具HotApp小程序统计也推出了带参数二维码 ...

  6. 小程序入口构造工具&二维码测试工具

    小程序入口构造工具&二维码测试工具 本文将介绍我们小程序中隐藏的两个工具页面.原理虽不复杂,收益却实实在在,或许也能给诸君带来启发. 入口构造工具 痛点 PM&运营 投放链接 PM&a ...

  7. jquery-qrcode客户端二维码生成类库扩展--融入自定义Logo图片

    年后换了部门,现在主要的职责就是在网上卖精油,似乎这个就是传说中的网络营销. 跟着公司的MM们也了解不了少关于网络营销的知识,间接的了解到马云和刘强东都是些怎样龌龊的人,尽管之前也这样认为. 淘宝就不 ...

  8. 【Win】Clso QR Tool 二维码小工具

    一个可以生成并识别二维码的windows小工具,纯绿色.不含糖. 可以通过输入文本生成二维码,或者加载本地图片.剪贴板内的图片,直接解析出二维码内容. 支持自定义LOGO. 下载文件 (当前版本:1. ...

  9. python笔记 利用python 自动生成条形码 二维码

    1. ean13标准条形码 from pystrich.ean13 import EAN13Encoder encode = EAN13Encoder(') encode.save('d:/barco ...

随机推荐

  1. java 面试经典题

    面向对象编程(OOP) Java是一个支持并发.基于类和面向对象的计算机编程语言.下面列出了面向对象软件开发的优点: 代码开发模块化,更易维护和修改. 代码复用. 增强代码的可靠性和灵活性. 增加代码 ...

  2. A New Stone Game POJ - 1740

    题目链接:https://vjudge.net/problem/POJ-1740#author=0 题意:有n堆石子,每次你可以选一堆拿走任意数量的石子,而且你还可以选择从这一堆剩下石子中取任意数量石 ...

  3. java.lang.IllegalArgumentException: MALFORMED

    java.lang.IllegalArgumentException: MALFORMED at java.util.zip.ZipCoder.toString(ZipCoder.java:58) a ...

  4. 全网最详细的Linux命令系列-cd命令

    Linux cd 命令可以说是Linux中最基本的命令语句,其他的命令语句要进行操作,都是建立在使用 cd 命令上的. 所以,学习Linux 常用命令,首先就要学好 cd 命令的使用方法技巧. 命令格 ...

  5. [贪心]D. 【例题4】国王游戏

    D . [ 例 题 4 ] 国 王 游 戏 D. [例题4]国王游戏 D.[例题4]国王游戏 解析 贪心思想,考虑交换后的值比交换前的小. 然后数据规模用高精度 Code #include <b ...

  6. Go Protobuf(比xml小3-10倍, 快20-100倍)

    简介 Protocol Buffers是什么? protocol buffers 是一种灵活,高效,自动化机制的结构数据序列化方法-可类比 XML,但是比 XML 更小.更快.更为简单.你可以定义数据 ...

  7. Python-Tkinter 使用for循环生成列表式Button及函数调用

    Tkinter是轻量级的图形化界面,在使用中我们可能遇到需要生成一串Button按钮的情况,如图: 如果一个一个操作就太麻烦了,但我们可以通过for循环列表的形式来实现 来看看以下例子: from t ...

  8. Dynamics CRM安装教程一:域环境准备

    服务器环境:Windows Service 2016 Stand Windows域是计算机网络的一种形式,其中所有用户账户,计算机,打印机和其他安全主体都在位于称为域控制器的一个或多个中央计算机集群上 ...

  9. AutoAssign源码分析

    目录 AutoAssign源码分析 一. 简介 二. 论文理论 2.1 联合表示 2.2 正样本权重 2.3 负样本权重 2.4 总的loss 2.5 补充loss 三. 论文代码 四. 总结 五. ...

  10. BUAA_OO_第二单元

    BUAA_OO_2020_UNIT2 一.程序结构分析 第五次作业 UML & Mertrics ​ 电梯的调度问题,实质上就是任务的请求与分配问题,笔者在第五次作业中采用简单的"生 ...