公司使用贸易通,5.6版本增加了自定义表情,但是比较郁闷的是表情只能一个一个添加,于是想可以不可以直接把q的自定义表情挖点过来用,于是有了下文。
原理分析:
查yahoo知识堂得知自定义表情保存地址为
自定义表情保存在: 安装路径/ users/用户名/ CustomEmotions下。
http://ks.cn.yahoo.com/question/1307082700391.html
我机器上此目录是C:\Program Files\阿里巴巴\贸易通\users\cnalichnsuddymail\CustomEmotions
进入目录,发现每个表情都是一大一小两个图片,小的一个是大的一个名字加上fixed.bmp
大的则是原图。
另个比较有看头的文件则是CustomEmotions.idx
分析得知这个很有可能是存放自定义表情数据的,
分析结构如下
前面16个字节为固定值,其中,第五个字节(从零算起)为16进制存储的自定义表情数量。
其余15个字节则为固定值,如下:
A8C500005F0000001800000018000000
接下去则为各个表情的数据
结构如下:
快捷键+1字节0x00+小图名(小图以原图+fixed.bmp结尾)+216个0x00+原本文件名(即大图名)+221个0x00
查看qq自定义表情发现文件名方式相同,于是动手copyQQ下自定义表情到旺旺表情目录,程序实现CustomEmotions.idx的改写实现表情的批量导入
关键代码如下
FaceAdd.java
package org.suddymail.addFace;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.FilenameFilter;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Iterator;
/**
* <P>Title: FaceAdd.java<P>
* <P>Description: 增加face库相关操作<P>
* <P>Copyright: Copyright (c) 2007<P>
* <P>@author suddymail<P>
* <P>@version 1.0<P>
*/
public class FaceAdd {
/**
* Descript: 生成要加入CustomEmotions.idx的串数据
* 070914ps: 首两个字节0xa8 0xc5用char转换后在string会丢失,只好不科学的放在写函数那单独写两个字节
*
* @param name
* @return
* @return String
*/
public static String CreateFaceString(ArrayList<String> name){
StringBuilder tmp1 = new StringBuilder();
for(int i=0; i<216; i++){
tmp1.append("\0");
}
StringBuilder tmp2 = new StringBuilder();
for(int i=0; i<221; i++){
tmp2.append("\0");
}
StringBuilder str = new StringBuilder();
//str.delete(0, 3);
str.append((char)0x00);
str.append((char)0x00);
str.append((char)name.size()); //可能是表情数
str.append((char)0x00);
str.append((char)0x00);
str.append((char)0x00);
str.append((char)0x18);
str.append((char)0x00);
str.append((char)0x00);
str.append((char)0x00);
str.append((char)0x18);
str.append((char)0x00);
str.append((char)0x00);
str.append((char)0x00);
Iterator<String> it = name.iterator();
while(it.hasNext()){
String tmp = it.next();
if(tmp.length()>=12)
str.append(tmp.substring(0,8)+"\0"+tmp.substring(0,tmp.length()-4)+"\0"+tmp.substring(0,tmp.length()-4).toLowerCase()+"fixed.bmp");
else
str.append(tmp.substring(0,tmp.length()-4)+"\0"+tmp.substring(0,tmp.length()-4)+"\0"+tmp.substring(0,tmp.length()-4).toLowerCase()+"fixed.bmp");
str.append(tmp1.toString());
str.append(tmp.substring(0,tmp.length()-4).toLowerCase()+tmp.substring(tmp.length()-4));
str.append(tmp2.toString());
}
return str.toString();
}
/**
* Descript: 根据指定path来得到目录下所有jpg或gif的文件名list
*
* @param path
* @return
* @return ArrayList<String>
*/
public static ArrayList<String> CreateNameArray(String path){
ArrayList<String> name = new ArrayList<String>();
//File f=new File("C://Program Files//阿里巴巴//贸易通//users//cnalichnsuddymail//CustomEmotions//");
File f = new File(path);
File[]ff= f.listFiles(new FilenameFilter(){
public boolean accept(File dir, String name) {
// TODO Auto-generated method stub
return name.toLowerCase().matches(".*.gif|.*.jpg");//里面可以替换成任何正则表达式
}
});
for(int i=0; i<ff.length; i++){
System.out.println(ff[i].getName());
name.add(ff[i].getName());
}
return name;
}
/**
* Descript: 把扫描结果写入数据文件
*
* @param path
* @param context
* @return
* @return boolean
*/
public static boolean WriteFile(String path, String context){
//FileWriter out = null;
FileOutputStream out = null;
try{
//out = new FileWriter(path+"CustomEmotions.idx");
out = new FileOutputStream(path+"CustomEmotions.idx");
out.write(0xa8);
out.write(0xc5);
out.write(context.getBytes());
//out.write(context);
out.close();
return true;
}catch (Exception e) {
// TODO: handle exception
System.out.println("File Write Error!");
return false;
}
}
/**
* Descript: 主操作函数
*
* @return void
*/
public static void Create(){
String path = "C://Program Files//阿里巴巴//贸易通//users//cnalichnsuddymail//CustomEmotions//";
ArrayList<String> name = FaceAdd.CreateNameArray(path);
String context = FaceAdd.CreateFaceString(name);
FaceAdd.WriteFile(path, context);
}
/**
* Descript: 带参数版,从外部获取需要的路径
*
* @param path
* @return void
*/
public static void Create(String path){
//String path = "C://Program Files//阿里巴巴//贸易通//users//cnalichnsuddymail//CustomEmotions//";
ArrayList<String> name = FaceAdd.CreateNameArray(path);
String context = FaceAdd.CreateFaceString(name);
FaceAdd.WriteFile(path, context);
}
public static void main(String[] args) {
System.out.printf(System.getProperty("user.dir")+"\\");
FaceAdd.Create(System.getProperty("user.dir")+"\\");
//FaceAdd.Create();
//String tmp = "abcdefghi.jpg";
//System.out.println(tmp.substring(0,8)+"\0x00"+tmp.substring(0,tmp.length()-4)+"fix.bmp");
/*File f=new File("C://Program Files//阿里巴巴//贸易通//users//cnalichnsuddymail//CustomEmotions//");
File[]ff= f.listFiles(new FilenameFilter(){
public boolean accept(File dir, String name) {
// TODO Auto-generated method stub
return name.toLowerCase().matches(".*.gif|.*.jpg");//里面可以替换成任何正则表达式
}
});
for(int i=0; i<ff.length; i++){
System.out.println(ff[i].getName());
}*/
}
}
因为没弄图形界面,所以想法是直接放到表情目录下运行通过获取当前路径得到表情目录。
附上工程代码和编译好的jar(java1.5以上,把q自定义表情图片(一大一小两张一组)拷贝到旺旺表情目录后,把jar放在旺旺表情目录双击即可)
#1