看图软件是openKylin操作系统上一款开源的图像查看软件,支持对图片进行基本操作,如:缩放、翻转、详情查看、复制、打印、重命名等,同时还可以对图片进行裁剪、存储、标注和ocr(文字识别)。
图1 看图软件界面
作为图像查看软件,查看图片是其基本功能,也是最重要的功能。在看图软件V1.2.0版本中,新增了10种图片格式(exr,psd,jfi,jif,jng,wbmp,xbm,xpm,jp2,j2k)的查看和保存,这些格式在技术上都是通过FreeImage库实现的。下面将为大家着重介绍看图软件中所使用的图片编解码库—FreeImage。
1.看图软件图片编解码库介绍
openKylin系统中的看图软件目前共支持30种图片格式,分别为:bmp,jpeg,jpg,jpe,pnm,pgm,ppm,pbm,sr,ras,dib,png,apng,gif,webp,tga,svg,ico,tiff,tif,exr,psd,jfi,jif,jng,wbmp,xbm,xpm,jp2,j2k。
为支持上述图片格式,看图软件使用以下库进行图片编解码:opencv库,FreeImage库,apng库,gif库等。其中,一半格式的图片使用的是大家比较熟悉的opencv库编解码,个别格式的图片,如svg等有自己的相关库。除此之外都是使用的FreeImage库进行图片的读写。在使用过程中,我们发现,对上层应用来说FreeImage库快速便捷,易于使用。
2.FreeImage库介绍
FreeImage库是一款开源的,免费的和跨平台的图片编解码库。支持对20多种流行图形格式的处理,如BMP 、JPEG 、GIF 、PNG 、TIFF等。
使用FreeImage库时要安装libfreeimage-dev和libfreeimageplus-dev。同时,FreeImage库提供了很多获取位图信息的接口,具有快速、灵活、简单易用的特点。FreeImage库中的所有函数都是以FreeImage_开头,如图像文件的读写函数分别为FreeImage_Load 和FreeImage_Save ,并且和opencv之间相互转换也很简单,感兴趣的小伙伴可前往FreeImage官网查看更多详情。
3.使用FreeImage库加载图片
看图软件在加载或操作一张图片的整个过程都是以cv::mat矩阵来存储图片的。打开一张图片时,看图软件使用FreeImage库加载图片的完整流程如下所示:
1. 获取图片真实格式;
2. 判断图片是否支持FreeImage读入;
3. FreeImage加载图片,获得FIBITMAP;
4. 将FIBITMAP转换为cv::mat;
5. 从内存中删除libfreeimage载入的图片,防止内存泄漏。
3.1 获取图片真实格式
在操作图片时,图片后缀可能是.xbm,.sr等,但这并不代表图片是xbm或sr格式,此时需要先通过库函数来获取图片的真实格式。
// 用库获取文件格式,path是图片的路径。 QByteArray temp_path; temp_path.append(path.toUtf8()); FREE_IMAGE_FORMAT format = FreeImage_GetFileType(temp_path.data());
FreeImage_GetFileType:由文件头拿到文件类型。参数:图片路径。
这个函数的返回值是FREE_IMAGE_FORMAT。可以从下图看到,返回值也可能是FIF_UNKNOWMN。
图2 图片类型
如果从库函数中解析出来的文件格式为FIF_UNKNOWMN,我们会从文件数据的角度,通过判断文件头,再次解析图片格式,提升拿到正确文件格式的成功率。
QFile file(path); if (!file.open(QIODevice::ReadOnly)) { return FIF_UNKNOWN; } const QByteArray data = file.read(64); /* Check bmp file */ if (data.startsWith("BM")) { s return FIF_BMP; } //path为图片路径
3.2 判断是否支持读入
在拿到文件类型后,加载图片之前,我们还需要做一个工作:判断该格式是否可以被FreeImage库读取。其中FreeImage_FIFSupportsReading用来判断是否支持该位图类型的读操作。
3.3 加载图片
假设我们已经拿到图片的正确格式,且该格式可以被FreeImage库读取。则调用库函数FreeImage_Load 加载位图,返回值为FIBITMAP。FIBITMAP数据结构保存着位图信息和像素数据,是FreeImage的核心。
3.4 将FIBITMAP转换成mat
在看图软件中,读写图片的整个流程的数据都是以cv::mat矩阵进行传递的。之所以使用cv::mat是为了之后能够对看图软件现有的功能进行扩展,尤其是opencv提供的AI方向。
图3 看图软件结构
因此,在拿到FreeImage返回的FIBITMAP后,我们需要将它转换为cv::mat。
FIBITMAP转换成cv::mat时,首先要看构造一个图片的mat矩阵都需要什么参数。
Mat(int rows, int cols, int type, void* data, size_t step=AUTO_STEP);//行数rows,列数cols,类型type,指向用户数据的指针data,每行占据的字节数。
所以,接下来我们的任务就是,从FIBITMAP拿到需要的所有参数。
1. int rows, int cols
对于行数和列数,FreeImage有函数可以直接调用,得到行列。
FIBITMAP *dib; int width = FreeImage_GetWidth(dib); int height = FreeImage_GetHeight(dib);
2. inttype
对于type,需要稍微做一下处理。FreeImage库提供了查看图片深度和数据类型的方法。
int bpp = FreeImage_GetBPP(src);//图片的深度 FREE_IMAGE_TYPE fit = FreeImage_GetImageType(src);//返回位图的数据类型
拿到FreeImage的类型的枚举值后,一一对应转为cv::mat的数据类型即可。
图4 数据类型
3. void* data
指向用户数据的指针data。
库中同样有可以直接调用的函数。
FreeImage_GetBits(FIBITMAP *dib):返回一个指向位图的数据位的指针
4. size_t step
step 每行占据的字节数
FreeImage_GetPitch(FIBITMAP *dib):返回位深度或线宽度(又叫做扫描宽度)。是以字节为单位返回对齐到下一个32位字节边界的位图宽度。
FIBITMAP *dib; int step = FreeImage_GetPitch(dib);
3.5内存释放
FIBITMAP *dib; FreeImage_Unload(dib);//从内存中删除载入图片,防止内存泄漏
除了FreeImage库外,目前还有许多优秀的图片编解码库,openKylin看图软件后续会适配更多的图片库来支持更多格式,并利用opencv的特性来扩展一些特色功能。各位小伙伴敬请期待吧!
openKylin(开放麒麟)社区旨在以“共创”为核心,在开源、自愿、平等、协作的基础上,通过开源、开放的方式与企业构建合作伙伴生态体系,共同打造桌面操作系统顶级社区,推动Linux开源技术及其软硬件生态繁荣发展。
社区首批理事成员单位包括麒麟软件、普华基础软件、中科方德、麒麟信安、凝思软件、一铭软件、中兴新支点、元心科技、中国电科32所、技德系统、北京麟卓、先进操作系统创新中心等13家产业同仁和行业机构。
来源:openKylin
审核:openKylin