FreeImage简介
FreeImage is an Open Source library project for developers who would like to support popular graphics image formats like PNG, BMP, JPEG, TIFF and others as needed by today‘s multimedia applications. FreeImage is easy to use, fast, multithreading safe, compatible with all 32-bit or 64-bit versions of Windows, and cross-platform (works both with Linux and Mac OS X).
简单地说就是一个跨平台的轻量图片库。貌似cocos2d用的图片加载的库就是这个。
编译
环境 - Windows 8.1
VS2008 (为了编译这个专门装的)
源码下载好,解压之后根目录下就有编译的工程文件,直接打开编译就好了。Debug和Release都编译一遍。
编译好之后就有FreeImage.dll, FreeImage.lib, FreeImaged.dll, FreeImaged.lb.
接下来编译C++ 的Wraper。
打开这个工程,X:\FreeImageSource\Wrapper\FreeImagePlus\FreeImagePlus.2008.sln
和刚才一样,Debug和Release都编译一遍。
接下来编译C++ Wraper的 测试工程
X:\FreeImageSource\Wrapper\FreeImagePlus\test\fipTest.2008.sln
将最外面的test.jpg拷贝到运行目录,挨个执行四个测试。
可能遇到的问题
找不到头文件
在这里添加头文件的目录
找不到lib
在下面的位置添加
这不到dll
将对应的dll拷贝到程序运行目录
测试程序崩溃
将test.jpg拷贝到运行目录。
简单使用
创建一个工程,还有要用到一张图片。
(Please call me LeiFeng.)
首先来最简单的,加载一张JPEG图片。
#include "stdafx.h" #include <iostream> #include "FreeImagePlus.h" int _tmain(int argc, _TCHAR* argv[]) { FreeImage_Initialise(TRUE); FIBITMAP * JPEG = FreeImage_Load(FIF_JPEG, "test.jpg", JPEG_DEFAULT); //获取影像的宽高,都以像素为单位 int Width = FreeImage_GetWidth(JPEG); int Height = FreeImage_GetHeight(JPEG); std::cout << "Width: " << Width << "\nHeight: " <<Height << std::endl; FreeImage_Unload(JPEG); FreeImage_DeInitialise(); return 0; }
颜色调整
常见的图片颜色调整FreeImage都已经实现,调用对应的接口就可以了。这里调用一个反色,还有一个调整曲线。
(容我先擦一下鼻血)
代码
FreeImage_AdjustContrast(JPEG, 15.0); FreeImage_AdjustBrightness(JPEG, 50.0); //FreeImage_Invert(JPEG); if (JPEG) { FreeImage_Save(FIF_BMP, JPEG, "test.bmp", BMP_DEFAULT); }
gif的拷贝
从一张gif生成一张一模一样的gif
BOOL bMemoryCache = TRUE; fipMultiPage src(bMemoryCache); fipMultiPage dst(bMemoryCache); // You MUST declare this before using it. // We will use the assignement operator, i.e. operator=() fipImage image; // Open src file (read-only, use memory cache) src.open("example.gif", FALSE, TRUE); if (src.isValid()) { // Open dst file (creation, use memory cache) dst.open("output.gif", TRUE, FALSE); // Get src page count int count = src.getPageCount(); // Clone src to dst for (int page = 0; page < count; page++) { // Load the bitmap at position ‘page‘ image = src.lockPage(page); if (image.isValid()) { // add a new bitmap to dst dst.appendPage(image); // Unload the bitmap (do not apply any change to src) src.unlockPage(image, FALSE); } } } std::cout << FreeImage_GetPageCount(dst) << std::endl; // Close src src.close(0); // Save and close dst dst.close();
查看gif的metadate
fipMultiPage src(bMemoryCache); src.open("example.gif", FALSE, TRUE); fipImage image; image = src.lockPage(0); fipMetadataFind finder; if (finder.findFirstMetadata(FIMD_ANIMATION, image, tagg)) { do { // process the tag const void * p = tagg.getValue(); DWORD* pp = (DWORD *)p; cout << "process the tag :" << tagg.getKey() << " " <<tagg.getType()<< " " << *pp << endl; tagVector.push_back(tagg); } while (finder.findNextMetadata(tagg)); }
最后用完记得unlockPage.
随便加载一个gif,得到对用的tag有下面这些
其中最重要的是FrameTime,表示帧占用的时间,单位是毫秒。其次是Loop,是一只循环播放(0)还是循环一次(1),
从静态图片生成gif
先下载几个png
这个问题卡了我将近一天,文档上全是坑。
先上文档中专门说gif生成的代码
// assume we have an array of dibs which are already 8bpp and all the same size, // and some float called fps for frames per second FIMULTIBITMAP *multi = FreeImage_OpenMultiBitmap(FIF_GIF, "output.gif", TRUE, FALSE); DWORD dwFrameTime = (DWORD)((1000.0f / fps) + 0.5f); for(int i = 0; i < 10; i++ ) { // clear any animation metadata used by this dib as we’ll adding our own ones FreeImage_SetMetadata(FIMD_ANIMATION, dib[i], NULL, NULL); // add animation tags to dib[i] FITAG *tag = FreeImage_CreateTag(); if(tag) { FreeImage_SetTagKey(tag, "FrameTime"); FreeImage_SetTagType(tag, FIDT_LONG); FreeImage_SetTagCount(tag, 1); FreeImage_SetTagLength(tag, 4); FreeImage_SetTagValue(tag, &dwFrameTime); FreeImage_SetMetadata(FIMD_ANIMATION, dib[i], FreeImage_GetTagKey(tag), tag); FreeImage_DeleteTag(tag); } FreeImage_AppendPage(multi, dib[i]); } FreeImage_CloseMultiBitmap(multi);
似乎先创建一个multiBitmap,然后各种appendPage就可以了。
Too Young.
先看一下gif的文件格式
GIF格式,是为使图片能够应用在在线(online)应用程序上所特别开发的图片格式。Gif,有时也被成为“Giff”,是一种无损,8位图片格式。“无损”是指100%的保持原始图片的像素数据信息。专业名词“8位”是指,所能表现的颜色深度——一个8位图像仅最多只能支持256种不同颜色(一个多余256种颜色的图片若用gif图片保存会出现失真)。
So,上面的那个png是32bit的,不是8位的图片是Append不上的,那就转格式呗。
自带一个convertTo8Bits的方法,但是转换出来是灰度的。
上论坛搜索答案,告知就是这样的。
要用一个colorQuantize方法,结果完全无效,上论然搜,告知要24位的图片才能转。
继续转呗,透明的部分全部变黑。
论坛上搜索无果,回头继续看png的格式
PNG图片类型
PNG格式有8位、24位、32位三种,下面是一些术语:
索引透明:类似于GIF,某一像素只有全透和全不透明两种效果
Alpha透明:半透明
PNG8 - 8位的PNG最多支持256(2的8次方)种颜色,8位的PNG支持索引透明和alpha透明。
PNG24 - 支持2的24次方种颜色,但不支持透明信息。
PNG32 - 32位的PNG在24位的PNG基础上增加了8位的透明信息,因此支持不同程度的半透效果。
默默地打开屁艾斯(PS),加载图片,存储为Web所用格式。
重新用代码记载,appendpage,全世界都安静了。
代码清单(用的plus的wraper)
#include "stdafx.h" #include <iostream> #include "FreeImagePlus.h" using namespace std; int _tmain(int argc, _TCHAR* argv[]) { BOOL bMemoryCache = TRUE; fipMultiPage dst(bMemoryCache); fipImage image1; image1.load("11.png"); fipImage image2; image2.load("2.png"); fipImage image3; image3.load("3.png"); image2.convertTo24Bits(); image2.colorQuantize(FIQ_WUQUANT); image3.convertTo24Bits(); image3.colorQuantize(FIQ_WUQUANT); float fps = 3.0f; DWORD dwFrameTime = (DWORD)((1000.0f / fps) + 0.5f); fipTag tag; tag.setKey("FrameTime"); tag.setType(FIDT_LONG); tag.setCount(1); tag.setLength(4); tag.setValue(&dwFrameTime); const void * p = tag.getValue(); DWORD* pp = (DWORD *)p; cout << "Tag" << tag.getKey() << " " << *pp << endl; //Set the loop of gif 0->loop forever 1->loop only once. DWORD bloop = (DWORD)(1); fipTag loopTag; loopTag.setKey("Loop"); loopTag.setType(FIDT_LONG); loopTag.setCount(1); loopTag.setLength(4); loopTag.setValue(&bloop); image1.setMetadata(FIMD_ANIMATION, tag.getKey(), tag); image2.setMetadata(FIMD_ANIMATION, tag.getKey(), tag); image3.setMetadata(FIMD_ANIMATION, tag.getKey(), tag); image1.setMetadata(FIMD_ANIMATION, loopTag.getKey(), loopTag); image2.setMetadata(FIMD_ANIMATION, loopTag.getKey(), loopTag); image3.setMetadata(FIMD_ANIMATION, loopTag.getKey(), loopTag); dst.open("output.gif", TRUE, FALSE); dst.appendPage(image1); dst.appendPage(image2); dst.appendPage(image3); dst.close(); return 0; }
最终效果,guang~
第一张png是由ps导出的8位png,后面的两张用代码转的8位。