C# 微信海報

weixin_34377065發表於2016-10-28

   最近悟出來一個道理,在這兒分享給大家:學歷代表你的過去,能力代表你的現在,學習代表你的將來。我們都知道計算機技術發展日新月異,速度驚人的快,你我稍不留神,就會被慢慢淘汰!因此:每日不間斷的學習是避免被淘汰的不二法寶。

   十年河東十年河西,莫欺少年窮。

   最近微信開發依然是那麼火,有人請我開發一個微信海報,拿到需求後,我瞬間笑了,這不就是兩年前我學習微信的時候自己做的一個案例嗎?能有什麼技術含量?

   當然,我有點自大了,所謂驕兵必敗,我們還是來分析分析這個微信海報吧!

   所謂微信海報就是一個圖片,這個圖片上有粉絲的專屬二維碼,有粉絲的頭像及商戶宣傳的廣告等。

   我做的微信海報如下圖:

   

   看到嗎?上邊有我的專屬二維碼,不過這個二維碼是臨時的,我做的有效期是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(給點打賞哦) 註明為什麼加我哦

   @陳臥龍的部落格

相關文章