最近悟出來一個道理,在這兒分享給大家:學歷代表你的過去,能力代表你的現在,學習代表你的將來。我們都知道計算機技術發展日新月異,速度驚人的快,你我稍不留神,就會被慢慢淘汰!因此:每日不間斷的學習是避免被淘汰的不二法寶。
十年河東十年河西,莫欺少年窮。
最近微信開發依然是那麼火,有人請我開發一個微信海報,拿到需求後,我瞬間笑了,這不就是兩年前我學習微信的時候自己做的一個案例嗎?能有什麼技術含量?
當然,我有點自大了,所謂驕兵必敗,我們還是來分析分析這個微信海報吧!
所謂微信海報就是一個圖片,這個圖片上有粉絲的專屬二維碼,有粉絲的頭像及商戶宣傳的廣告等。
我做的微信海報如下圖:
看到嗎?上邊有我的專屬二維碼,不過這個二維碼是臨時的,我做的有效期是7天(看了最新的開發者文件,目前臨時二維碼可以支援30天了)話說,騰訊也真是閒的蛋疼,專屬二維碼還分什麼臨時二維碼和永久二維碼,依稀記得,微信剛推出的時候,臨時二維碼只有N小時,後來感覺滿足不了客戶的需求,增加為7天,再後來,就是現在,支援30天!你們說說,騰訊這不是閒著蛋疼嗎?直接給個永久的不就行了嗎?
說到上述話題,我抱怨了騰訊,其實就該好好噴噴騰訊製作的開發文件,到處是坑,到處忽悠。如果你不幸成為了一名微信開發者,那麼至少你會有一段時間頭疼。不說別的,在這兒我就想噴微信的客服系統。微信剛開始的客服系統是多客服系統,就是那種CS的軟體,類似於QQ,需要線上安裝的,說實在的,這個多客服用著那不是一般的爽,不是一般的方便,你可以在PC上使用,也可以繫結在手機上使用,方便極了。後來騰訊360度大轉彎,說什麼運營成本高,不堪重負之類的話,硬生生的改成了現如今雞肋般的網頁版客服系統,那個體驗效能不是一般的差啊,所以,我想代表廣大客戶及開發者對騰訊說句髒話:RNMB,能不能穩定點?能不能全心全意為客戶,開發者服務?
話說多了,騰訊做的差,你可以不用啊。哎,小胳膊擰不過大腿,我們還是得老老實實的用,我還是得老老實實的講解這種海報的生成!
首先分析下這個海報:
1、首先你得有個模板圖片<這個模板圖片留出兩處空白,供二維碼和頭像佔用>
2、微信帶引數二維碼的生成
3、粉絲頭像的獲取及下載
以上就是合成所需的基本圖片
4、C#圖片合成
5、上傳合成的圖片至伺服器並獲取MediaID
6、根據MediaID,將圖片傳送給粉絲
上述便是生成這張海報所需的資源及知識點,我們一步一步來哈
1、首先,模板圖片,找公司PS高手,做一個就行
2、微信帶引數二維碼的生成(我提供的方法是直接貼上的,不能直接用,有需要的,可以以打賞的模式,我發給你原始碼)
#region 獲取用於換取二維碼的Ticket /// <summary> /// 獲取用於換取二維碼(臨時二維碼和長久二維碼)的Ticket /// </summary> /// <param name="senceId">場景值ID</param> /// <param name="type">值為:long 時:代表長久性二維碼 值為short時:代表臨時二維碼</param> /// <returns></returns> public static string GeterweimaTicket(int senceId, string type = "short") { string Ticket = ""; CreateQrCodeResult re = new CreateQrCodeResult(); try { if (type == "short")//臨時二維碼 { re = QrCodeApi.Create(IsExistAccess_Token2(), 604800, senceId); } else { re = QrCodeApi.Create(IsExistAccess_Token2(), 0, senceId); } Ticket = re.ticket; } catch { if (type == "short")//臨時二維碼 { Ticket = CreateTicket(IsExistAccess_Token2()); } else { Ticket = CreateLongTicket(IsExistAccess_Token2()); } } return Ticket; } #region 原方法 /// <summary> /// 建立二維碼ticket 臨時二維碼 /// </summary> /// <returns></returns> public static string CreateTicket(string TOKEN) { string result = ""; string strJson = @"{""expire_seconds"": 604800, ""action_name"": ""QR_SCENE"", ""action_info"": {""scene"": {""scene_id"": 321}}}"; string wxurl = "https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token=" + TOKEN + ""; result = GetPage(wxurl, strJson); result = GetJsonValue(result, "ticket");//獲取票據 ////LogHelper.WriteLog(result); return result; } /// <summary> /// 獲取永久二維碼Ticket /// </summary> /// <param name="TOKEN"></param> /// <returns></returns> public static string CreateLongTicket(string TOKEN) { string result = ""; string strJson = @"{""action_name"": ""QR_LIMIT_SCENE"", ""action_info"": {""scene"": {""scene_id"": 123}}}"; string wxurl = "https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token=" + TOKEN + ""; result = GetPage(wxurl, strJson); result = GetJsonValue(result, "ticket");//獲取票據 ////LogHelper.WriteLog(result); return result; } //{"ticket":"gQFw8DoAAAAAAAAAASxodHRwOi8vd2VpeGluLnFxLmNvbS9xL3pFZ3lETjdsMVNDcy1DRW9PMmE3AAIEP1TcVAMECAcAAA==","expire_seconds":1800,"url":"http:\/\/weixin.qq.com\/q\/zEgyDN7l1SCs-CEoO2a7"} /// <summary> /// 通過ticket換取二維碼 /// </summary> /// <param name="TICKET">票據</param> /// <param name="openId">二維碼依照openId 命名</param> /// <param name="Pth">相對路徑 @"\weixin\HuLu\erweima2"</param> /// <returns>下載二維碼成功後的物理路徑:D:\XXXXXX.com\kkk\erweima2\201503031044566511190.jpg</returns> public static string GetTicketImage(string TICKET, string openId, string Pth) { string content = string.Empty; string strpath = string.Empty;//生成的URL 也就是 關注的URL string savepath = string.Empty;//圖片儲存的路徑 string stUrl = "https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=" + HttpContext.Current.Server.UrlEncode(TICKET); HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create(stUrl); req.Method = "GET"; using (WebResponse wr = req.GetResponse()) { HttpWebResponse myResponse = (HttpWebResponse)req.GetResponse(); strpath = myResponse.ResponseUri.ToString(); WebClient mywebclient = new WebClient(); // @" savepath = HttpContext.Current.Server.MapPath(Pth) + "\\" + openId + "." + myResponse.ContentType.Split('/')[1].ToString(); // //LogHelper.WriteLog(savepath); try { mywebclient.DownloadFile(strpath, savepath);//下載生成的二維碼圖片 } catch (Exception ex) { savepath = ex.ToString(); LogHelper.WriteLog("錯誤了" + savepath); } } //LogHelper.WriteLog(savepath.ToString() + "都給我滾!"); return savepath.ToString(); } #endregion #endregion
3、獲取使用者頭像並下載:
#region 獲取使用者的詳細資訊 /// <summary> /// 獲取使用者的詳細資訊 /// </summary> /// <param name="REFRESH_TOKEN">Token</param> /// <param name="OPENID">使用者的OpenId</param> /// <returns>str</returns> public static Dictionary<string, object> Get_UserInfo(string REFRESH_TOKEN, string OPENID) { // Response.Write("獲得使用者資訊REFRESH_TOKEN:" + REFRESH_TOKEN + "||OPENID:" + OPENID); string UserInfo = GetJson("https://api.weixin.qq.com/cgi-bin/user/info?access_token=" + REFRESH_TOKEN + "&openid=" + OPENID); Dictionary<string, Object> obj2 = JsonConvert.DeserializeObject<Dictionary<string, Object>>(UserInfo); return obj2; } protected static string GetJson(string url) { WebClient wc = new WebClient(); wc.Credentials = CredentialCache.DefaultCredentials; wc.Encoding = Encoding.UTF8; string returnText = wc.DownloadString(url); if (returnText.Contains("errcode")) { //可能發生錯誤 } //Response.Write(returnText); return returnText; } #endregion
使用者資訊用有個HeardImage 就是粉絲的頭像路徑,然後根據這個路徑,我們把它下載下來!
public class HttpDownLoad { private long fileLength; private long downLength;//已經下載檔案大小,外面想用就改成公共屬性 private static bool stopDown; public HttpDownLoad() { fileLength = 0; downLength = 0; stopDown = false; // // TODO: 在此處新增建構函式邏輯 // } /// <summary> /// 檔案下載 /// </summary> /// <param name="url">連線</param> /// <param name="fileName">本地儲存檔名</param> public void httpDownFile(string url, string fileName) { stopDown = false; Stream str = null, fs = null; try { //獲取下載檔案長度 fileLength = getDownLength(url); downLength = 0; if (fileLength > 0) { WebClient DownFile = new WebClient(); str = DownFile.OpenRead(url); //判斷並建立檔案 if (createFile(fileName)) { byte[] mbyte = new byte[1024]; int readL = str.Read(mbyte, 0, 1024); fs = new FileStream(fileName, FileMode.OpenOrCreate, FileAccess.Write); //讀取流 while (readL != 0) { if (stopDown) break; downLength += readL;//已經下載大小 fs.Write(mbyte, 0, readL);//寫檔案 readL = str.Read(mbyte, 0, 1024);//讀流 //progressBar.Value = (int)(downLength * 100 / fileLength); //label.Text = progressBar.Value.ToString() + "%"; //System.Windows.Forms.Application.DoEvents(); } str.Close(); fs.Close(); } } } catch (Exception ex) { if (str != null) str.Close(); if (fs != null) fs.Close(); } } /// <summary> /// 檔案下載 /// </summary> /// <param name="url">連線</param> /// <param name="fileName">本地儲存檔名</param> public void httpDownFile2(string url, string fileName) { try { WebClient DownFile = new WebClient(); DownFile.DownloadFile(url, fileName); } catch (Exception ex) { throw ex; } } /// <summary> /// 獲取下載檔案大小 /// </summary> /// <param name="url">連線</param> /// <returns>檔案長度</returns> private long getDownLength(string url) { try { WebRequest wrq = WebRequest.Create(url); WebResponse wrp = (WebResponse)wrq.GetResponse(); wrp.Close(); return wrp.ContentLength; } catch (Exception ex) { return 0; throw ex; } } /// <summary> /// 建立檔案(檔案如已經存在,刪除重建) /// </summary> /// <param name="fileName">檔案全名(包括儲存目錄)</param> /// <returns></returns> private bool createFile(string fileName) { try { if (File.Exists(fileName)) { File.Delete(fileName); } Stream s = File.Create(fileName); s.Close(); return true; } catch (Exception ex) { return false; throw ex; } } public void downClose() { stopDown = true; } }
呼叫LoadDowmFile()即可
此時:二維碼和頭像都生成了,我們就可以呼叫圖片合成的方法了<注意:此處需要二次圖片合成,第一次是模板和二維碼合成,第二次是把得到的新圖片和頭像再做一次合成>
#region C#圖片處理 合併圖片 /// <summary> /// 呼叫此函式後使此兩種圖片合併,類似相簿,有個 /// 背景圖,中間貼自己的目標圖片 /// </summary> /// <param name="sourceImg">貼上的源圖片</param> /// <param name="destImg">貼上的目標圖片</param> /// 使用說明: string pic1Path = Server.MapPath(@"\testImg\wf.png"); /// 使用說明: string pic2Path = Server.MapPath(@"\testImg\yj.png"); /// 使用說明: System.Drawing.Image img = CombinImage(pic1Path, pic2Path); /// 使用說明:img.Save(Server.MapPath(@"\testImg\Newwf.png")); public static System.Drawing.Image CombinImage(string sourceImg, string destImg) { System.Drawing.Image imgBack = System.Drawing.Image.FromFile(sourceImg); //相框圖片 System.Drawing.Image img = System.Drawing.Image.FromFile(destImg); //照片圖片 //從指定的System.Drawing.Image建立新的System.Drawing.Graphics Graphics g = Graphics.FromImage(imgBack); g.DrawImage(imgBack, 0, 0, 148, 124); // g.DrawImage(imgBack, 0, 0, 相框寬, 相框高); g.FillRectangle(System.Drawing.Brushes.Black, 16, 16, (int)112 + 2, ((int)73 + 2));//相片四周刷一層黑色邊框 //g.DrawImage(img, 照片與相框的左邊距, 照片與相框的上邊距, 照片寬, 照片高); g.DrawImage(img, 17, 17, 112, 73); GC.Collect(); return imgBack; } #endregion
最後就是上傳至伺服器並獲取MediaId和傳送給粉絲了,這一塊相信大家都比較熟悉,不作多的解釋!
還有一些個人總結的好方法,也是公共的方法,貼給大家:
#region XML KEY /// <summary> /// XML KEY 通用方法 /// </summary> /// <returns></returns> public static string GetXMLstrByKey(string Key, XmlDocument xml) { object strValue = xml.SelectSingleNode("xml").SelectSingleNode(Key).InnerText; if (strValue != null) { return strValue.ToString(); } else { return ""; } } #endregion
#region 獲取接收事件推送的XML結構 /// <summary> /// 獲取接收事件推送的XML結構 /// </summary> /// <returns></returns> public static XmlDocument GetMsgXML() { Stream stream = HttpContext.Current.Request.InputStream; byte[] byteArray = new byte[stream.Length]; stream.Read(byteArray, 0, (int)stream.Length); string postXmlStr = System.Text.Encoding.UTF8.GetString(byteArray); XmlDocument xmldoc = new XmlDocument(); xmldoc.LoadXml(postXmlStr); return xmldoc; } #endregion #region 傳送客服訊息 //1 傳送文字訊息 //2 傳送圖片訊息 //3 傳送語音訊息 //4 傳送視訊訊息 //5 傳送音樂訊息 //6 傳送圖文訊息 /// <summary> /// 傳送客服訊息 /// </summary> /// <param name="posturl">請求的URL</param> /// <param name="postData">傳送的資料 Json格式</param> /// <returns>json格式的字串 通過獲取Key為:errcode的值,判斷accessToken是否過期,如果返回值為:40001 則accessToken無效,需要重新獲取。例項程式碼:請參考WX_SendNews類</returns> public static string GetPage(string posturl, string postData) { //WX_SendNews news = new WX_SendNews(); //posturl: news.Posturl; //postData:news.PostData; System.IO.Stream outstream = null; Stream instream = null; StreamReader sr = null; HttpWebResponse response = null; HttpWebRequest request = null; Encoding encoding = Encoding.UTF8; byte[] data = encoding.GetBytes(postData); // 準備請求... try { // 設定引數 request = WebRequest.Create(posturl) as HttpWebRequest; CookieContainer cookieContainer = new CookieContainer(); request.CookieContainer = cookieContainer; request.AllowAutoRedirect = true; request.Method = "POST"; request.ContentType = "application/x-www-form-urlencoded"; request.ContentLength = data.Length; outstream = request.GetRequestStream(); outstream.Write(data, 0, data.Length); outstream.Close(); //傳送請求並獲取相應迴應資料 response = request.GetResponse() as HttpWebResponse; //直到request.GetResponse()程式才開始向目標網頁傳送Post請求 instream = response.GetResponseStream(); sr = new StreamReader(instream, encoding); //返回結果網頁(html)程式碼 string content = sr.ReadToEnd(); string err = string.Empty; return content; } catch (Exception ex) { string err = ex.Message; return string.Empty; } } #endregion #region 獲取Json字串某節點的值 /// <summary> /// 獲取Json字串某節點的值 /// </summary> public static string GetJsonValue(string jsonStr, string key) { string result = string.Empty; if (!string.IsNullOrEmpty(jsonStr)) { key = "\"" + key.Trim('"') + "\""; int index = jsonStr.IndexOf(key) + key.Length + 1; if (index > key.Length + 1) { //先截逗號,若是最後一個,截“}”號,取最小值 int end = jsonStr.IndexOf(',', index); if (end == -1) { end = jsonStr.IndexOf('}', index); } result = jsonStr.Substring(index, end - index); result = result.Trim(new char[] { '"', ' ', '\'' }); //過濾引號或空格 } } return result; } #endregion
好啦,就是這麼多,如果需要製作海報的具體方法,請加我微信:18137070152(給點打賞哦) 註明為什麼加我哦
@陳臥龍的部落格