国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁(yè) > 學(xué)院 > 開(kāi)發(fā)設(shè)計(jì) > 正文

編程實(shí)現(xiàn)QQ表情文件CFC格式

2019-11-18 16:57:07
字體:
來(lái)源:轉(zhuǎn)載
供稿:網(wǎng)友

背景:最近閑來(lái)無(wú)事,也應(yīng)論壇某會(huì)員要求,想做個(gè)QQ表情下載的站點(diǎn)。本來(lái)事情是很簡(jiǎn)單的,寫(xiě)個(gè)小小的CRUD也就可以了,但嘻哈呵嘿既然是個(gè).Net程序員,當(dāng)然要使用.Net來(lái)實(shí)現(xiàn)了。今天我們就用.Net來(lái)實(shí)現(xiàn)CFC ( custom face cab? ) 的表情格式的打包功能。

要做到這個(gè)功能,我們必須先了解這個(gè)格式,首先Google一下。我們找到了這一篇來(lái)自清華大學(xué)的文章:FC文件格式詳解

從這篇文章里我們得知了CFC的文件格式大概如下:

 

一個(gè)塊有15個(gè)字段,如下

md5的字符串形式長(zhǎng)度,4個(gè)字節(jié)
快捷鍵長(zhǎng)度,4字節(jié)
表情名稱長(zhǎng)度,4字節(jié)
表情文件名長(zhǎng)度,4字節(jié)
表情文件長(zhǎng)度,4字節(jié)
微縮圖文件名長(zhǎng)度,4字節(jié)
微縮文件長(zhǎng)度,4字節(jié)
表情文件幀數(shù),4字節(jié)
圖片md5的字符串形式
快捷鍵
表情名稱
表情文件名
微縮圖文件名
表情文件內(nèi)容
微縮圖內(nèi)容
知道了格式就好辦了,我們按步就班定義一個(gè)結(jié)構(gòu)(struct)
 1    Struct#region Struct
 2    public struct FaceBlock
 3    {
 4        public uint MD5Length; //32
 5        public uint uintcutLength; //4
 6        public uint FaceNameLength; //4
 7        public uint FaceFileNameLength; //36 md5 + extension
 8        public uint FileLength;
 9        public uint ThumbnailFileNameLength; //41 md5 + fixed.bmp
10        public uint ThumbnailFileLength;
11        public uint FrameLength;
12        public string MD5;
13        public string uintcuts;
14        public string FaceName;
15        public string FaceFileName;
16        public string ThumbnailFileName;
17        public byte[] FaceData;
18        public byte[] ThumbnailData;
19
20        public static FaceBlock FromImage(string file)
21        {
22            return FaceHelper.GetFaceBlockFromImage(file);
23        }
24
25        byte[] GetBytes(uint value)
26        {
27            byte[] bt = BitConverter.GetBytes(value);
28            List<byte> bytes = new List<byte>();
29            bytes.AddRange(bt);
30            if (bytes.Count < 4)
31            {
32                int l = 4 - bytes.Count;
33                for (int i = 0; i < l; i++)
34                    bytes.Add((byte)0);
35            }
36            return bytes.ToArray();
37        }
38
39        public byte[] ToBytes()
40        {
41            List<byte> bytes = new List<byte>();
42            Encoding e = Encoding.ASCII;
43            bytes.AddRange(GetBytes(MD5Length));
44            bytes.AddRange(GetBytes(uintcutLength));
45            bytes.AddRange(GetBytes(FaceNameLength));
46            bytes.AddRange(GetBytes(FaceFileNameLength));
47            bytes.AddRange(GetBytes(FileLength));
48            bytes.AddRange(GetBytes(ThumbnailFileNameLength));
49            bytes.AddRange(GetBytes(ThumbnailFileLength));
50            bytes.AddRange(GetBytes(FrameLength));
51
52            bytes.AddRange(e.GetBytes(MD5));
53            bytes.AddRange(e.GetBytes(uintcuts));
54            bytes.AddRange(e.GetBytes(FaceName));
55            bytes.AddRange(e.GetBytes(FaceFileName));
56            bytes.AddRange(e.GetBytes(ThumbnailFileName));
57
58            bytes.AddRange(FaceData);
59            bytes.AddRange(ThumbnailData);
60
61            return bytes.ToArray();
62        }
63    }
64    #endregion其中含有兩方法,一個(gè)是從文件得到一個(gè)此結(jié)構(gòu)的靜態(tài)方法,另一個(gè)是將此結(jié)構(gòu)轉(zhuǎn)化為byte數(shù)組。

我們?cè)俳ㄒ粋€(gè)類,命名為:FaceHelper
代碼如下:
    public class FaceHelper
    {
        internal static FaceBlock GetFaceBlockFromImage(string file)
        {
            FaceBlock fb = new FaceBlock();
            //打開(kāi)文件流  
            FileStream fs = new FileStream(file, FileMode.Open, Fileaccess.Read);
            //獲取圖像
            Image img = Image.FromStream(fs);
            //獲得一個(gè)20*20的縮略圖
            Image thumbnail = img.GetThumbnailImage(20, 20, null, IntPtr.Zero);
            MemoryStream ms = new MemoryStream();
            //將縮圖圖轉(zhuǎn)化數(shù)byte數(shù)組
            thumbnail.Save(ms, System.Drawing.Imaging.ImageFormat.Bmp);
            byte[] thumbnailData = ms.ToArray();
            ms.Close();
            ms.Dispose();
            thumbnail.Dispose();

            //得到一個(gè)唯一的MD5字符串
            string md5 = GetMD5(fs);
            //文件名,格式為:md5 + 擴(kuò)展名
            string fileName = string.Format("{0}{1}", md5, Path.GetExtension(file));
            //縮略圖文件名,格式為:md5 + fixed.bmp
            string thumbnailName = string.Format("{0}fixed.bmp", md5);
            //隨機(jī)設(shè)置一個(gè)快捷鍵
            string uintcuts = "qq.5inet.net_" + RandomNum(6);
            fs.Close();
            fs.Dispose();

            //取得總的幀數(shù)
System.Drawing.Imaging.FrameDimension fd = System.Drawing.Imaging.FrameDimension.Resolution;
            int frameCount = img.FrameDimensionsList.Length;
            img.Dispose();

            fb.MD5 = md5;
            fb.MD5Length = (uint)md5.Length;
            fb.uintcuts = uintcuts;
            fb.uintcutLength = (uint)uintcuts.Length;
            fb.FaceName = uintcuts;
            fb.FaceNameLength = (uint)uintcuts.Length;
            fb.FaceFileName = fileName;
            fb.FaceFileNameLength = (uint)fileName.Length;
            fb.ThumbnailFileName = thumbnailName;
            fb.ThumbnailFileNameLength = (uint)thumbnailName.Length;
            fb.FaceData = File.ReadAllBytes(file);
            fb.FileLength = (uint)fb.FaceData.Length;
            fb.ThumbnailData = thumbnailData;
            fb.ThumbnailFileLength = (uint)thumbnailData.Length;
            fb.FrameLength = (uint)frameCount;

            return fb;
        }

        Helper#region Helper
        //隨機(jī)方法
        internal static string RandomNum(int n) //
        {
            string strchar = "0,1,2,3,4,5,6,7,8,9";
            string[] VcArray = strchar.Split(',');
            string VNum = "";//由于字符串很短,F(xiàn)77pclw,c絡(luò)G|?,業(yè),e'b就不用StringBuilder了
            int temp = -1;    //記錄上次隨機(jī)數(shù)值,盡量避免產(chǎn)生幾個(gè)一樣的隨機(jī)數(shù)
            //采用一個(gè)簡(jiǎn)單的算法以保證生成隨機(jī)數(shù)的不同
            Random rand = new Random();
            for (int i = 1; i < n + 1; i++)
            {
                if (temp != -1)
                {
                    rand = new Random(i * temp * unchecked((int)

                 DateTime.Now.Ticks));
                }
                //int t =  rand.Next(35) ;
                int t = rand.Next(10);
                if (temp != -1 && temp == t)
                {
                    return RandomNum(n);
                }
                temp = t;
                VNum += VcArray[t];
            }
            return VNum;//返回生成的隨機(jī)數(shù)
        }

        //從文件名獲得MD5
        internal static string GetMD5(FileStream fs)
        {
            MD5CryptoServicePRovider md5 = new MD5CryptoServiceProvider();
            byte[] md5byte = md5.ComputeHash(fs);
            string str = string.Empty;
            int i, j;
            foreach (byte b in md5byte)
            {
                i = Convert.ToInt32(b);
                j = i >> 4;
                str += (Convert.ToString(j, 16));
                j = ((i << 4) & 0x00ff) >> 4;
                str += (Convert.ToString(j, 16));
            }

            return str.ToUpper();
        }
        #endregion

        //從一個(gè)目錄生成一個(gè)CFC文件集合
        public static void
BuildCFCFileFromDirectory(string directory)
        {
            List<byte> bytes = new List<byte>();
            foreach (string file in Directory.GetFiles(directory))
            {
                if (!IsImageFile(file))
                    continue;

                bytes.AddRange(FaceBlock.FromImage(file).ToBytes());
            }

            string fName = Path.Combine(directory, Path.GetDirectoryName(directory) + ".cfc");
            FileStream fs = File.Create(fName);
            fs.Write(bytes.ToArray(), 0, bytes.Count);
            fs.Close();
        }

        //判斷是否為圖像文件,方法比較簡(jiǎn)陋。
        private static bool IsImageFile(string file)
        {
            List<string> validExt = new List<string>(new string[]{
                ".bmp",
                ".jpg",
                ".jpeg",
                ".gif",
                ".png",
            });

            return validExt.Contains(Path.GetExtension(file).ToLower());
        }
    }
好,有了上面的方法,我們就可以調(diào)用了。
調(diào)用方法實(shí)在是有些簡(jiǎn)單。

FaceHelper.BuildCFCFileFromDirectory(Server.MapPath("~/img/"));
這樣就OK了,現(xiàn)在去你的網(wǎng)站根目錄下看看,有沒(méi)有一個(gè)img.cfc的文件呢?再雙擊一下,是不是將img目錄下的文件全部導(dǎo)入到QQ表情里了呢? enjoy coding!

本文原發(fā):無(wú)垠IT教學(xué)網(wǎng)
http://m.survivalescaperooms.com/skyover/archive/2006/10/03/520581.html


發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 洛隆县| 遂平县| 余庆县| 年辖:市辖区| 潜山县| 霍城县| 伊宁县| 陈巴尔虎旗| 乐亭县| 商河县| 泾阳县| 柏乡县| 东丰县| 克东县| 惠州市| 康马县| 徐水县| 濉溪县| 阳西县| 兴城市| 图木舒克市| 兴化市| 西吉县| 米易县| 池州市| 临潭县| 汝阳县| 乌什县| 日照市| 惠水县| 秀山| 明溪县| 东平县| 万全县| 霍林郭勒市| 贵阳市| 舞钢市| 色达县| 长春市| 莱州市| 佛教|