前言
FreeImage 是一个很知名的免费图形库,其支持格式非常多样,常见的如: bmp, gif, ico, jpeg, png, tiff, webp, psd
等文档均可读取。
近日需编写一个小工具用于在Windows下读取大量不同格式的图片转换为jpeg
,就使用了FreeImage
库,但在实际使用中碰到一个问题,非常诡异,此文做简单记录。
0x01 问题
在读取带透明通道的图片,如png
等32bit
的位图时,若直接存储为FIF_JPEG
此类24bit
位图时会出现莫名其妙的内存越界错误,具体为访问了已经释放的内存,致进程挂死,但目标文件会被创建,只是无内容。
由于我通过动态库的方式引用,不好调试,查阅文档也没看到FreeImage_Save
函数有相关方面的说明。
0x02 解决方案
最终推测并尝试多个方法,发现需将32bit
(带透明通道)的位图先通过FreeImage_ConvertTo24Bits
方法转换为24bit
位图,再操作这个24bit
的位图即可保存为FIF_JPEG
格式。
如下代码,将多种格式的图片读取进来,再转换为24bit
位图后缩放至指定大小再保存为jpeg
,但每一步都有失败的可能,需要增加容错处理。
FREE_IMAGE_FORMAT format = FreeImage_GetFileTypeU(filename);
FIBITMAP *fib = FreeImage_LoadU(format, filename);
FIBITMAP *fib24 = FreeImage_ConvertTo24Bits(fib);
FIBITMAP *res = FreeImage_Rescale(fib24, fileRes.width(), fileRes.height());
FreeImage_SaveU(FIF_JPEG, res, m_targetFilePath.toStdWString().c_str())
不负责任的猜测原因有可能是多出来的透明通道在保存过程中被当做普通数据访问并欲写入文件导致的。
0x03 附言
FreeImage
库比较老,有一个C++
的Warpper
,但由于文档中都是C Style
的风格,于是就没有用了。在使用过程中,发现很多函数都返回一个新的FIBITMAP
,感觉内存泄露的危险性还蛮大的。
另外在Windows下读写需要用FreeImage_LoadU
和FreeImage_SaveU
以wchar_t
的方式读写。