分享
 
 
 

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

王朝other·作者佚名  2008-05-30
窄屏简体版  字體: |||超大  

背景:最近闲来无事,也应论坛某会员要求,想做个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

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有