NEWS

新闻

了解openKylin最新资讯,关注社区和产品动态。

NEWS

Learn about the latest news.

【小白课程】以openKylin看图软件为例,浅谈图片编解码库—FreeImage

2023-02-02 09:40:02

看图软件是openKylin操作系统上一款开源的图像查看软件,支持对图片进行基本操作,如:缩放、翻转、详情查看、复制、打印、重命名等,同时还可以对图片进行裁剪、存储、标注和ocr(文字识别)。

openKylin(开放麒麟)

图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。

openKylin(开放麒麟)

图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方向。

openKylin(开放麒麟)

图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的数据类型即可。

openKylin(开放麒麟)

图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(开放麒麟)


openKylin(开放麒麟)社区旨在以“共创”为核心,在开源、自愿、平等、协作的基础上,通过开源、开放的方式与企业构建合作伙伴生态体系,共同打造桌面操作系统顶级社区,推动Linux开源技术及其软硬件生态繁荣发展。

社区首批理事成员单位包括麒麟软件、普华基础软件、中科方德、麒麟信安、凝思软件、一铭软件、中兴新支点、元心科技、中国电科32所、技德系统、北京麟卓、先进操作系统创新中心等13家产业同仁和行业机构。



来源:openKylin

审核:openKylin