最近看到一则新闻说小米收购了MSNLite(hada.me)团队,打算开发PC端的米聊客户端,于是对MSNLite产生了兴趣,同时也在自己的机器上安装了MSNLite,乖乖,使用了几天确实感觉她比以前的MSN快多了,并且功能强大,无广告;但唯一让我感觉不足的是表情包太难找了(不知是不是我的搜索技术不过关)。找来找去发现在她的官方论坛上有一篇关于表情包的解释(http://bbs.hada.me/thread-1045-1-10.html)。于是有了自己写一个表情包制作工具的想法(其实这个制作工具她的论坛上也有一个,好像不是很稳定),程序源于生活,就当是练练手:
从官网的信息可以知道,MSNLite的表情包MEP实质上是ZIP格式的重命名,唯一多了一个索引文件MsnliteEmoticons.dat(UTF-8):用于引导表情图片的批量导入;从网上下载一些可用的MEP包重命名ZIP然后解压查看MsnliteEmoticons.dat文件内容,发现格式如下:
Emoticons { .......... $ee1d5f { local_path 2d27536e0981cec8f6654f3f638e0cfe.gif desc b11 group 百度Hi熊表情包 } $d32a6c { local_path 253faad76aea56ae371e1642bc556044.gif desc b12 group 百度Hi熊表情包 } ........ } SaveTimes 1然后对比导入后的表情编辑窗体,如下:
从中是不是可以很轻易的发现什么?
由上可推断出MSNLite的MEP表情包索引文件格式如下:
Emoticons { .......... 快捷方式 { local_path 索引文件相对表情图片路径 desc 表情描述 group 所属性分组 } ........ } SaveTimes 1 # 这个我猜想是保存次数,但只要保证它为1就应该可行了现在是不是就可以开始动手大干一场了?嘿嘿。先别急,还是先简单的介绍一下Java的ZIP压缩所要用到的几个类(当然了,如果你已经了解了这方面的知识,你就跳过去直接进入编码阶段吧):
实现ZIP要导入java.util.zip包中的ZipFile,ZipOutputStream,ZipInputSream和ZipEntry类。
而在每一个压缩文件中都会存在多个子文件,每个子文件在Java中使用的就是ZipEntry表示。
一般压缩要用到ZipOutputStream和ZipEntry两个类,先由文件流创建一个ZipOutputStream对象,再将每一个文件包装成ZipEntry对象,接着调用ZipOutputStream对象的putNextEntry()方法为压缩文件
建立一个各ZipEntry条目,最后将其对应文件的内容写入到ZipOutputStream对象流中,这样就可以实现了压缩。
好了讲了这样多的废话,现在那就直奔主题直接帖上我的代码(我想其实不用我给,聪明的你都可以自己编写了),如下:
import java.io.*; import java.util.zip.*; import java.util.Random; import java.util.Scanner; import java.util.List; import java.util.ArrayList; import java.util.regex.Pattern; public class MSNListEmoticonsCreater { // Store some valid keyboard character private char[] keyCodes = new char[]{'a','b','c','d','e','f','g','h','i', 'j','k','l','m','n','o','p','q','r', 's','t','u','v','w','x','y','z', 'A','B','C','D','E','F','G','H','I', 'J','K','L','M','N','O','P','Q','R', 'S','T','U','V','W','X','Y','Z', '!','^','&','{','}','$','<','>',',', '.','?','|','_','+','*','(',')','#', ':',';','@','%'}; /* * Get user input information */ public String getInputString() { Scanner userIn = new Scanner(System.in); String inText = userIn.nextLine(); return inText; } /* * Filter get emoticons files */ private List<File> getAllEmoticonsFiles(File directory) { File[] listFiles = directory.listFiles(); List<File> emoticons = new ArrayList<File>(); for(int i=0; i<listFiles.length; i++) { String filename = listFiles[i].getName().toLowerCase(); String tempName = ""; if(filename.matches(".*.(bmp|jpg|jpeg|png|gif)$")) { /*if (filename.matches(".*[^a-zA-Z_0-9.].*")) { tempName = filename.replaceAll("[^a-zA-Z_0-9.]",""); listFiles[i] = rename(listFiles[i], tempName); System.out.println(listFiles[i]); System.out.println("====New===>"+tempName); }*/ if(listFiles[i]!=null) emoticons.add(listFiles[i]); } } if(!emoticons.isEmpty()) return emoticons; return null; } /* * Rename a File */ private File rename(File file, String name) { String filename = file.getName(); //int index = filename.lastIndexOf("."); //String fileType = filename.substring(index+1).toLowerCase(); String newFileName = file.getParent()+"/"+name; if(file.renameTo(new File(newFileName))) { return new File(newFileName); } return null; } /* * Generate a shortcut key string */ private String generateShortCut(int seed) { Random rad = new Random(); int idx1 = rad.nextInt(keyCodes.length-1); int idx2 = rad.nextInt(keyCodes.length-1); return "$"+keyCodes[idx1]+String.valueOf(seed)+keyCodes[idx2]; } /* * Compressed files */ private void zip(File[] listFiles, String zipFilePath) throws IOException { File zipFile = new File(zipFilePath); if(!zipFile.exists()) zipFile.createNewFile(); ZipOutputStream zipOut = new ZipOutputStream(new FileOutputStream(zipFile)); byte[] buff = new byte[1024]; for(int i=0; i<listFiles.length; i++) { InputStream input = new FileInputStream(listFiles[i]); ZipEntry zipEntry = new ZipEntry(listFiles[i].getName()); zipOut.putNextEntry(zipEntry); int len = 0; while((len=input.read(buff))!=-1) { zipOut.write(buff, 0, len); zipOut.flush(); } System.out.println("Compressed <--- "+listFiles[i].getAbsoluteFile()); input.close(); } System.out.println("Compress succeed and generate MSNList emoticons package: "+zipFile.getAbsoluteFile()); zipOut.close(); } /* * Create a MSNList emoticons package */ public void createMSNListEmoticonsPkg(File dir, String groupName) throws IOException { List<File> emoticons = getAllEmoticonsFiles(dir); if(emoticons==null||emoticons.isEmpty()) throw new IOException("There haven't image file(*.bmp,*.jpg,*.jpeg,*.png, *.gif):"+dir.getAbsoluteFile()); String indexFilePath = dir.getAbsoluteFile()+"/"+"MsnliteEmoticons.dat"; File indexFile = new File(indexFilePath); if(!indexFile.exists()) indexFile.createNewFile(); PrintWriter writer = new PrintWriter(indexFile); writer.println("Emoticons\r\n{"); for(int i=0; i<emoticons.size(); i++) { File emoticon = emoticons.get(i); String shortcut = generateShortCut(i+1); writer.println("\t\""+shortcut+"\"\r\n\t{"); // shortcut key writer.println("\t\tlocal_path "+emoticon.getName()); // file path writer.println("\t\tdesc \""+groupName+(i+1)+"\""); // description writer.println("\t\tgroup \""+groupName+"\""); // the group name writer.println("\t}"); } writer.println("}\r\nSaveTimes 1"); writer.close(); emoticons.add(indexFile); File[] files = new File[emoticons.size()]; files = emoticons.toArray(files); zip(files, groupName+".mep"); } public static void main(String[] args) { MSNListEmoticonsCreater test = new MSNListEmoticonsCreater(); System.out.print("Please input an image directory path: "); String dirPath = test.getInputString(); File dir = new File(dirPath); if(dir.exists()&&dir.isDirectory()) { System.out.print("Specified a name for the group of emoticons: "); String groupName = test.getInputString(); if(groupName.trim().length()>0) { try { test.createMSNListEmoticonsPkg(dir, groupName); } catch(IOException e) { e.printStackTrace(); } } else { System.out.println("The group Name can't is empty!"); } } else { System.out.println("Directory Not Found: Please make sure your input is valid emoticons directory!\r\n"+ dir); } } }上面的代码的使用方法,是先要创建一个表情目录,将一些需要添加的图片统一放到里面,然后运行本程序,在终端中先告诉它刚新建表情目录的路径,然后再为将要生成的表情组份输入一个名字,这样它就会在你的程序目录下生成一个“组份名.mep”的文件,这就是最后需要导入到MSNLite的表情包。
唉,写了这样多的代码发现上面的代码存在一个严重的缺陷就是不支持中文,也就是说在你新建的表情目录及组份名时最好指定的是英文名,真是硬伤,关键是我不知道怎样实现Java的编码转换,如果聪明的你知道,欢迎留言,O(∩_∩)O。
最终运行图片:
1.在桌面上新建一个名为qq的目录,存放表情图片:
2.运行本程序:
3.将生成的QQ.mep导入到MSNLite中:
大功告成!!
注:以上程序有点简陋,如有错误,欢迎批评指出,谢谢.
PS:最近最终发现了一个用于生成UTF-8文件的方法,因此可以扩展支持中文了,使用OutputStreamWriter对象,如下:
new OutputStreamWriter(new FileOutputStream(file), "UTF-8");