C++ BMP转JPG方法三
因为最近涉及将大的jpg缩小后再在网络上传输,所以需要将大的jpg转小的JPG。首先用Opencv将jpg读取到内存,缩小后,保存为bmp,再将bmp转JPG。如果直接是bmp文件也可以的。7万张图片从枚举到转换保存一共使用了半个小时。内存无泄露。
读取文件数据后创建IStream对象,再调用IStream类方法read将JPG数据以二进制流读取出来。
使用GetImageEncodersSize之前一定要初始化GDIplus。最好在函数里面
ULONG_PTR gdiplusToken;
Gdiplus::GdiplusStartupInput gdiplusStartupInput;
Gdiplus::GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
退出的时候记得
Gdiplus::GdiplusShutdown(gdiplusToken);
1.添加GDI头文件
- #include < Gdiplus.h>
- #pragma comment(lib, "Gdiplus.lib")
- using namespace Gdiplus;
- #include <Objbase.h>
- #include <Objidl.h>
- #pragma comment(lib, "Ole32.lib")
- #pragma comment(lib, "Uuid.lib")
2.定义两个公共函数:
- INT GetEncoderClsid(const WCHAR *format, CLSID *pClsid)
- {
- UINT num = 0; // number of image encoders
- UINT size = 0; // size of the image encoder array in bytes
- ImageCodecInfo* pImageCodecInfo = NULL;
- GetImageEncodersSize(&num, &size);
- if (size == 0){
- return -1; // Failure
- }
- pImageCodecInfo = (ImageCodecInfo*)(malloc(size));
- if (pImageCodecInfo == NULL){
- return -1; // Failure
- }
- GetImageEncoders(num, size, pImageCodecInfo);
- for (UINT j = 0; j < num; ++j){
- if (wcscmp(pImageCodecInfo[j].MimeType, format) == 0){
- *pClsid = pImageCodecInfo[j].Clsid;
- free(pImageCodecInfo);
- return j; // Success
- }
- }
- free(pImageCodecInfo);
- return -1; // Failure
- }
int n = 0;
void WriteJPGFile(BYTE *pData, DWORD dwLen)
{WCHAR wcPath[MAX_PATH] = {0};wsprintf(wcPath, L"F:\\test\\%d.jpg", ++n);HANDLE hFile = CreateFile(wcPath, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);if (hFile != INVALID_HANDLE_VALUE){DWORD dwWrite = 0;WriteFile(hFile, pData, dwLen, &dwWrite, NULL);CloseHandle(hFile);}
}
这个函数是将ipl缩小到指定宽高的上限。
void ResizeImage(IplImage **ipl, int nWidth, int nHeight)
{if (*ipl){while ((*ipl)->width >= nWidth || (*ipl)->height >= nHeight){DWORD dwWidth = (*ipl)->width / 2;DWORD dwHeight = (*ipl)->height / 2;IplImage* iplResize = cvCreateImage(cvSize(dwWidth, dwHeight), 8, 3);if (iplResize){cvResize((*ipl), iplResize);cvReleaseImage(&(*ipl));(*ipl) = cvCloneImage(iplResize);cvReleaseImage(&iplResize);}}}
}
转换函数:
Bitmap* IplImage2Bitmap(IplImage* pIplImg)
{if (!pIplImg){return NULL;}Gdiplus::Bitmap *pBitmap = ::new Gdiplus::Bitmap((int)pIplImg->width, (int)pIplImg->height, PixelFormat24bppRGB);if (!pBitmap){return NULL;}BitmapData bmpData;Rect rect(0, 0, pIplImg->width, pIplImg->height);pBitmap->LockBits(&rect, ImageLockModeWrite, PixelFormat24bppRGB, &bmpData);BYTE *pByte = (BYTE*)bmpData.Scan0;if (pIplImg->widthStep == bmpData.Stride){memcpy(bmpData.Scan0, pIplImg->imageDataOrigin, pIplImg->imageSize);}pBitmap->UnlockBits(&bmpData);return pBitmap;
}
void bmp2jpg(char cPath[MAX_PATH])
{IplImage *ipl = cvLoadImage(cPath);if (ipl){ResizeImage(&ipl, 300, 300);CLSID codecClsid;GetEncoderClsid(L"image/jpeg", &codecClsid);int iQuality = 100;EncoderParameters encoderParameters;encoderParameters.Count = 1;encoderParameters.Parameter[0].Guid = EncoderQuality;encoderParameters.Parameter[0].Type = EncoderParameterValueTypeLong;encoderParameters.Parameter[0].NumberOfValues = 1;encoderParameters.Parameter[0].Value = &iQuality;Bitmap*pBitmap = IplImage2Bitmap(ipl);if (pBitmap){IStorage* pIStorage = NULL;IStream* pJPGStream = NULL;HRESULT hr = StgCreateDocfile(NULL, STGM_READWRITE | STGM_CREATE | STGM_SHARE_EXCLUSIVE, 0, &pIStorage);if (SUCCEEDED(hr)){hr = pIStorage->CreateStream(L"StreamImage2", STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &pJPGStream);DWORD dwErr = GetLastError();if (SUCCEEDED(hr)){Status bStatus = pBitmap->Save(pJPGStream, &codecClsid);//将bmp转jpg后保存在内存中//Status bStatus = pImage.Save(L"f:\\1.jpg", &codecClsid);//如果是保存为文件则把注释去掉BYTE * pJPGData = NULL;while (!pJPGData){try{pJPGData = new BYTE[1024 * 1024];}catch (...){}}memset(pJPGData, 0, 1024 * 1024);LARGE_INTEGER move;move.QuadPart = 0;pJPGStream->Seek(move, STREAM_SEEK_SET, NULL);//定位到流的起始位置DWORD dwRead = 0;hr = pJPGStream->Read(pJPGData, 1024 * 1024, &dwRead);//在read之前必须seek。否则读取不出来数据WriteJPGFile(pJPGData, dwRead);delete[] pJPGData;}}// Get the class identifier for the JPEG encoder.if (pJPGStream){pJPGStream->Release();}if (pIStorage){pIStorage->Release();}::delete pBitmap;}else{OutputDebugString(L"图片转换失败");}cvReleaseImage(&ipl);}else{OutputDebugStringA(cPath);}
}
调用函数:
void CIplimageToBmpDlg::OnBnClickedButton1()
{WCHAR wcModule[MAX_PATH * 2] = { 0 };GetModuleFileName(NULL, wcModule, MAX_PATH * 2);::PathRemoveFileSpec(wcModule);if (::PathFileExistsW(wcModule)){wsprintf(wcModule + wcslen(wcModule), L"\\AD\\7万Bmp\\*.*");WIN32_FIND_DATAW FindFileData;HANDLE hFind = FindFirstFileW(wcModule, &FindFileData);if (hFind == INVALID_HANDLE_VALUE){return;}else{int nMAX_Ad_Pictures = 0;while (FindNextFileW(hFind, &FindFileData) != 0){WCHAR *p = PathFindExtension(FindFileData.cFileName);if (p){if (_wcsicmp(p, L".bmp") == 0 || _wcsicmp(p, L".jpg") == 0 || _wcsicmp(p, L".png") == 0){char cPath[MAX_PATH] = { 0 };WCHAR wcFilePath[MAX_PATH * 2] = { 0 };GetModuleFileName(NULL, wcFilePath, MAX_PATH * 2);::PathRemoveFileSpec(wcFilePath);wsprintf(wcFilePath + wcslen(wcFilePath), L"\\AD\\7万Bmp\\%s", FindFileData.cFileName);WideCharToMultiByte(CP_ACP, 0, wcFilePath, MAX_PATH, cPath, MAX_PATH, NULL, NULL);bmp2jpg(cPath);/*//将jpg转bmpwsprintf(wcFilePath + wcslen(wcFilePath), L"\\AD\\7万Bmp\\%s", FindFileData.cFileName);WideCharToMultiByte(CP_ACP, 0, wcFilePath, MAX_PATH, cPath, MAX_PATH, NULL, NULL);IplImage *ipl = cvLoadImage(cPath);if (ipl){char cPathPic[MAX_PATH] = {0};sprintf_s(cPathPic, "f:\\test\\%d.bmp", ++n);cvSaveImage(cPathPic, ipl);cvReleaseImage(&ipl);}*/}}}}// 查找结束FindClose(hFind);}AfxMessageBox(L"操作完成");
}
图片路径及图片都删除了
demo下载地址:http://download.csdn.net/detail/sz76211822/9819193
C++ BMP转JPG方法三相关推荐
- boostrap 鼠标滚轮滑动图片_BootStrap 轮播插件(carousel)支持左右手势滑动的方法(三种)...
Bootstrap 轮播(Carousel)插件是一种灵活的响应式的向站点添加滑块的方式.除此之外,内容也是足够灵活的,可以是图像.内嵌框架.视频或者其他您想要放置的任何类型的内容. 因为最近开发的项 ...
- Flash Builder4.7极其简单破解方法-三步搞定(亲测)
资讯类型: 转载 来源页面: http://weibo.com/2101024913/yvmR0D9Df 资讯原标题: 资讯原作者: 丿卓越丶星辰 翻译词数: 词 我的评论: 对这篇文你有啥看法,跟贴 ...
- python类的方法三种访问权_Python基础33-面向对象(继承资源(属性与方法)的使用注意)...
在Python中, 继承是指子类对父类资源的使用权 1 继承-属性与方法的使用权限 1.1 测试属性与方法分别如下 公有属性/方法 受保护属性/方法 私有属性/方法 class Animal: a = ...
- 垂直居中重要方法理解---重点是方法三
方法一 这个方法把一些 div 的显示方式设置为表格,因此我们可以使用表格的 vertical-align property 属性. <div id="wrapper"> ...
- 10038 mysql,关于MySql 10038错误的完美解决方法(三种)
第一种方法: 第一步: 先看报错窗口 2003 can't connect to MySQL server on '127.0.0.1'(10038). 第二步: 原因是:远程3306端口未对外开放操 ...
- FPGA复位激励编写(方法三)
1.1 FPGA复位激励编写(方法三) 1.1.1 本节目录 1)本节目录: 2)本节引言: 3)FPGA简介: 4)FPGA复位激励编写(方法三): 5)结束语. 1.1.2 本节引言 " ...
- FPGA时钟激励编写(方法三)
1.1 FPGA时钟激励编写(方法三) 1.1.1 本节目录 1)本节目录: 2)本节引言: 3)FPGA简介: 4)FPGA时钟激励编写(方法三) 5)结束语. 1.1.2 本节引言 "不 ...
- mysql 2003 10038_关于MySql10038错误的完美解决方法(三种)
第一种方法: 第一步: 先看报错窗口 2003 can't connect to MySQL server on '127.0.0.1'(10038). 第二步: 原因是:远程3306端口未对外开放操 ...
- Maven 无法下载依赖包的解决方法---三步dao!!!
Maven 无法下载依赖包的解决方法---三步dao!!! 参考文章: (1)Maven 无法下载依赖包的解决方法---三步dao!!! (2)https://www.cnblogs.com/WLCY ...
- 通俗易懂的Monte Carlo的积分方法(三)
通俗易懂的Monte Carlo的积分方法(三) 考虑曾经在参加MCM时的一个多重积分的计算难题 ∫∫D(H−z(x,y))21+zx2+zy2dσ\int\int_{D}(H-z(x,y))^2\s ...
最新文章
- 论如何优雅地进行工作安排
- 云栖大会变迁史(2009-2017)
- Python:if判断与while、for循环语句
- 无监督学习和半监督学习
- php 判断两个数组差集,php array_udiff_assoc 计算两个数组的差集实例
- python在工厂中的运用_在python中使用元类实现工厂设计模式
- 手机上网流量统计_数据统计 | 上半年手机流量同比增110.2%,你贡献了多少?
- mysql导入的excel更新_excel导入数据库,存在则更新不存在添加
- __attribute__((weak)):弱引用,可以不实现
- Tomcat学习总结(17)—— Tomcat生产环境中域名访问和连接MySQL
- struts环境搭建以及登陆功能的书写
- Kotlint集合简单总结
- 成都信息工程大学 809 软件工程导论简答题必背
- libcef-框架架构中概念介绍-命令行参数-元素布局-应用程序结构(二)
- Jenkins:安装出现“该jenkins实例似乎已离线”问题解决
- js 浏览器永久保存数据:localStorage
- Python办公自动化之文件读写操作与Excel,csv,PDF文件
- 抽取word中的背景图
- 菜狗杯Web签到wp
- mysql 最大值65536_SQL server事物复制报错:要复制的 LOB 数据的长度(xxxxx)超出了配置的最大值 65536...
热门文章
- 探究CSS3中的transition和transform属性方法使用
- asp.net md5加密
- plsql报错:Not logged on
- 计算机文档我的文档丢失,我的文档不见了怎么办?我的文档图标不见了找回方案...
- wordpress企业主题安装
- 浙大何越扬计算机系2 2,浙江大学第十一届大学生数学建模竞赛获奖名单.doc
- 圣丹斯电影节2019:讲故事,不断发展。
- 如何 自定义starter?
- strtok函数详解
- mysql创建表插入随机数_插入随机数到MySQL数据库