批量拆分图片透明通道
2015-07-05 22:17
183 查看
最近项目中遇到图片内存占用太大的问题。一种思路是将一张带有透明通道的图片拆分成两张,一张只包含RGB三个通道,另外一张只记录原图的A通道信息(可以用RGB任意通道),这样在Unity中经过压缩后的两幅图的大小也远比原来的带透明的图片小。于是自己实现了个cpp版的批量处理工具,话说好久不写cpp了写起来好难过啊。
这次用到的库是FreeImage。FreeImage是个轻量级的图像处理库,可以很方便地在像素级别处理图片。
这次用到的库是FreeImage。FreeImage是个轻量级的图像处理库,可以很方便地在像素级别处理图片。
#include <iostream> #include <io.h> #include <string> #include <stdio.h> #include <map> #include "FreeImage.h" #pragma comment(lib, "FreeImage.lib") using namespace std; //验证路径扩展名是否是png bool ValidFilePath(string path) { string::size_type dotPos = path.find_last_of('.'); if (dotPos == string::npos) return false; string fileExtra = path.substr(dotPos); if (0 == fileExtra.compare(".png")) return true; return false; } //验证图片是否有透明 bool ValidTexture(FIBITMAP *texture) { int width = FreeImage_GetWidth(texture); int height = FreeImage_GetHeight(texture); int bytespp = FreeImage_GetLine(texture) / width; if (bytespp != 4) return false; bool valid = false; FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(texture); for (int y = 0; y < height; y++) { BYTE *bits = FreeImage_GetScanLine(texture, y); for (int x = 0; x < width; x++) { if (bits[FI_RGBA_ALPHA] < 255) //有透明度小于255的像素 { valid = true; } bits += bytespp; } } return valid; } //生成新的文件名 string ChangeFileName(string path, string extra) { string newName = path; string::size_type dotPos = path.find_last_of('.'); if (dotPos == string::npos) return ""; newName.insert(dotPos, extra); return newName; } string ChangeFilePath(string path, string path2) { string::size_type linePos = path.find_last_of('\\'); if (linePos == string::npos) return ""; string fileName = path.substr(linePos); return path2.append(fileName); } bool Convert(string path, string dest) { if (path == "") return false; FreeImage_Initialise(TRUE); FREE_IMAGE_FORMAT fif = FreeImage_GetFileType(path.c_str()); if (FIF_UNKNOWN == fif) { fif = FreeImage_GetFIFFromFilename(path.c_str()); } if (FIF_UNKNOWN == fif) { cout << "File Not Support :" << path << endl; return false; } FIBITMAP* sourceTexture = NULL; if (FreeImage_FIFSupportsReading(fif)) { sourceTexture = FreeImage_Load(fif, path.c_str()); } if (sourceTexture == NULL) return false; if (!ValidTexture(sourceTexture)) return false; int width = FreeImage_GetWidth(sourceTexture); int height = FreeImage_GetHeight(sourceTexture); int bytespp = FreeImage_GetLine(sourceTexture) / width; //为生成的两幅图分配内存 FIBITMAP *rgbTexture = FreeImage_Clone(sourceTexture); FIBITMAP *aTexture = FreeImage_Clone(sourceTexture); for (int y = 0; y < height; y++) { //逐行扫描图片 BYTE *sourceBits = FreeImage_GetScanLine(sourceTexture, y); BYTE *rgbBits = FreeImage_GetScanLine(rgbTexture, y); BYTE *aBits = FreeImage_GetScanLine(aTexture, y); for (int x = 0; x < width; x++) { rgbBits[FI_RGBA_RED] = sourceBits[FI_RGBA_RED]; rgbBits[FI_RGBA_GREEN] = sourceBits[FI_RGBA_GREEN]; rgbBits[FI_RGBA_BLUE] = sourceBits[FI_RGBA_BLUE]; rgbBits[FI_RGBA_ALPHA] = 255; aBits[FI_RGBA_RED] = sourceBits[FI_RGBA_ALPHA]; aBits[FI_RGBA_GREEN] = sourceBits[FI_RGBA_ALPHA]; aBits[FI_RGBA_BLUE] = sourceBits[FI_RGBA_ALPHA]; aBits[FI_RGBA_ALPHA] = 255; //移动指针到下一个像素 sourceBits += bytespp; rgbBits += bytespp; aBits += bytespp; } } path = ChangeFilePath(path, dest); if (false == FreeImage_Save(FIF_PNG, rgbTexture, ChangeFileName(path, "_RGB").c_str(), PNG_DEFAULT)) { cout << "save RGB image error\n" << endl; } if (false == FreeImage_Save(FIF_PNG, aTexture, ChangeFileName(path, "_A").c_str(), PNG_DEFAULT)) { cout << "save A image error\n" << endl; } //释放句柄 FreeImage_Unload(sourceTexture); FreeImage_Unload(rgbTexture); FreeImage_Unload(aTexture); cout << "转换完成" << path << endl; return true; } void ConvertAll(string path, string dest) { map<string, string> paths; //递归遍历文件夹 _finddatai64_t file; intptr_t hFile; string curPath = path; curPath.append("\\*.*"); hFile = _findfirst64(curPath.c_str(), &file); if (-1 == hFile) { cout << "Find First Failed."<<endl; return; } do { if (1 == strlen(file.name) && file.name[0] == '.' || (strlen(file.name) == 2 && file.name[0] == '.' && file.name[1] == '.')) { //是当前目录或者上级目录 continue; } string filePath = path; filePath.append("\\").append(file.name); if (file.attrib & _A_SUBDIR) { //是文件夹,递归转换 ConvertAll(filePath, dest); } else { if (ValidFilePath(filePath)) { //paths.insert(filePath, dest); if (paths.find(filePath) == paths.end()) { paths[filePath] = dest; } } } } while (_findnext64(hFile, &file) == 0); _findclose(hFile); for (auto iter = paths.begin(); iter != paths.end(); ++iter) { Convert(iter->first, iter->second); } } int main(int argc, char** argv) { if (argc != 3) { cout << "命令行参数不对!" << endl; return -1; } cout << "开始处理所有图片,只能处理.png的图片" << endl; cout << argv[1] << " " << argv[2] << endl; ConvertAll(argv[1], argv[2]); cout << "所有图片处理完成" << endl; return 0; }
相关文章推荐
- JAVA中的反射机制
- android版微信href属性失效问题
- Ruby on Rails Tutorial 第二章 之 微博资源
- 更换磁阵硬盘,数据库宕机
- bfs最短路
- NGUI之刚体无限弹跳
- java之yield(),sleep(),wait()等区别
- 第6讲 Zend 整合数据库
- C# webbroswer屏蔽脚本错误
- 看<后海不是海>的随想
- guide
- Gensim官方教程翻译(五)——英文维基百科的实验
- HDU---Children's queue(递归解法)
- 【python学习笔记02】python的数据类型2
- thinkphp url重写
- The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods install
- OpenCV2.4.10+VS2013+Win8.1 64位配置
- 函数式编程
- Java程序日志二
- HTTP长连接与短连接