广

ASP编程

  • IOS开发
  • android开发
  • PHP编程
  • JavaScript
  • ASP.NET
  • ASP编程
  • JSP编程
  • Java编程
  • 易语言
  • Ruby编程
  • Perl编程
  • AJAX
  • 正则表达式
  • C语言
  • 编程开发

    编程实现QQ表情文件CFC格式

    2018-04-16 10:58:04 次阅读 稿源:互联网
    零七广告

      背景:最近闲来无事,也应论坛某会员要求,想做个QQ表情下载的站点。本来事情是很简单的,写个小小的CRUD也就可以了,但嘻哈呵嘿既然是个.Net程序员,当然要使用.Net来实现了。今天我们就用.Net来实现CFC ( custom face cab? ) 的表情格式的打包功能。

      要做到这个功能,我们必须先了解这个格式,首先Google一下。我们找到了这一篇来自清华大学的文章:FC文件格式详解

      从这篇文章里我们得知了CFC的文件格式大概如下:

       

      一个块有15个字段,如下

      md5的字符串形式长度,4个字节
      快捷键长度,4字节
      表情名称长度,4字节
      表情文件名长度,4字节
      表情文件长度,4字节
      微缩图文件名长度,4字节
      微缩文件长度,4字节
      表情文件帧数,4字节
      图片md5的字符串形式
      快捷键
      表情名称
      表情文件名
      微缩图文件名
      表情文件内容
      微缩图内容
      知道了格式就好办了,我们按步就班定义一个结构(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其中含有两方法,一个是从文件得到一个此结构的静态方法,另一个是将此结构转化为byte数组。

      我们再建一个类,命名为:FaceHelper
      代码如下:
          public class FaceHelper
          {
              internal static FaceBlock GetFaceBlockFromImage(string file)
              {
                  FaceBlock fb = new FaceBlock();
                  //打开文件流  
                  FileStream fs = new FileStream(file, FileMode.Open, FileAccess.Read);
                  //获取图像
                  Image img = Image.FromStream(fs);
                  //获得一个20*20的缩略图
                  Image thumbnail = img.GetThumbnailImage(20, 20, null, IntPtr.Zero);
                  MemoryStream ms = new MemoryStream();
                  //将缩图图转化数byte数组
                  thumbnail.Save(ms, System.Drawing.Imaging.ImageFormat.Bmp);
                  byte[] thumbnailData = ms.ToArray();
                  ms.Close();
                  ms.Dispose();
                  thumbnail.Dispose();

                  //得到一个唯一的MD5字符串
                  string md5 = GetMD5(fs);
                  //文件名,格式为:md5 + 扩展名
                  string fileName = string.Format("{0}{1}", md5, Path.GetExtension(file));
                  //缩略图文件名,格式为:md5 + fixed.bmp
                  string thumbnailName = string.Format("{0}fixed.bmp", md5);
                  //随机设置一个快捷键
                  string uintcuts = "qq.5inet.net_" + RandomNum(6);
                  fs.Close();
                  fs.Dispose();

                  //取得总的帧数
      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
              //随机方法
              internal static string RandomNum(int n) //
              {
                  string strchar = "0,1,2,3,4,5,6,7,8,9";
                  string[] VcArray = strchar.Split(',');
                  string VNum = "";//由于字符串很短,F77pclw,c络G|?,业,e'b就不用StringBuilder了
                  int temp = -1;    //记录上次随机数值,尽量避免产生几个一样的随机数
                  //采用一个简单的算法以保证生成随机数的不同
                  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;//返回生成的随机数
              }

              //从文件名获得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

              //从一个目录生成一个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();
              }

              //判断是否为图像文件,方法比较简陋。
              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());
              }
          }
      好,有了上面的方法,我们就可以调用了。
      调用方法实在是有些简单。

      FaceHelper.BuildCFCFileFromDirectory(Server.MapPath("~/img/"));
      这样就OK了,现在去你的网站根目录下看看,有没有一个img.cfc的文件呢?再双击一下,是不是将img目录下的文件全部导入到QQ表情里了呢? enjoy coding!

      本文原发:无垠IT教学网
      http://www.cnblogs.com/skyover/archive/2006/10/03/520581.html

    零七网部分新闻及文章转载自互联网,供读者交流和学习,若有涉及作者版权等问题请及时与我们联系,以便更正、删除或按规定办理。感谢所有提供资讯的网站,欢迎各类媒体与零七网进行文章共享合作。

    零七广告
    零七广告
    零七广告
    零七广告