2013年6月16日星期日

Qt4读取exif的一个轻量级C++库

    exif是jpeg的一个扩展。标准jpeg文件通常包含了很多个section,而exif信息就保存在其中一个section里。正如软件行业通常会遇到的情况,在未成为正式标准前总有许多厂商发表了各自的实现,exif也不例外,这就导致exif信息解析起来比较复杂。目前对exif支持最好也最有名的当属C语言写成的libexif了。
    我在EzViewer项目中,最开始是使用libexif库来解析exif信息的。但是libexif有许多缺点,例如库比较大(有1M左右),与C++对接比较麻烦,与Qt的国际化方式不兼容,api也很难用。事实上,使用libexif需要了解许多exif结构上的知识,学习成本比较高。因此后来决定换掉libexif。
    开始找到的替换方案是exiv2,这是一个有名的C++库。阻止我使用它的原因是这个库仍然比较大。后来又找到jhead,一个C语言的命令行程序,十分轻量(编译后只有几十K)。我一开始尝试将其简化并改造成库,也确实完成了,但用起来情况不理想:因为原先程序是为命令行设计的,因此没有很好的容错处理,一旦解析错误就直接退出,不利于程序中调用。
    最终我找到easyexif。easyexif是一个轻量级的纯C++库(源码只有几百行),专门用于解析exif信息。它的用法很简单:读取整个文件到内存中,调用EXIFInfo::parseFrom()方法对该内存进行解析,就可以获取一系列exif信息了。当然,easyexif也有缺点:1、因为是轻量级的,所以只支持标准exif的一些常见属性;2、需要将整个文件读入内存,即使那个文件可能不包含exif信息;3、EXIFInfo类对一些值没有进行初始化或初始值不正确,导致无法判断某些属性是否存在,无法复用EXIFInfo类。
    针对easyexif的这些缺点,我用Qt4写了一个类,包含下面功能:预先解析文件,借鉴jhead的代码判断是否jpeg格式、是否含有exif section、exif section的起始位置和长度,这样只在含有exif section时才将这个sectionn读入内存,传给EXIFInfo::parseFrom()进行解析。同时也结合exif规范文档对easyexif本身进行了修改,包括增加一些属性支持、更好的初始化以便复用EXIFInfo类。所有的代码可以在EzViewer源码中找到,主要是ImageHeader类和exif.h、exif.cpp文件。 ImageHeader类的用法可以参考其中ImageWrapper.cpp的attribute()方法。

参考:

文档信息

没有评论:

发表评论