C++ BMP转JPG方法三

本文介绍了一种利用OpenCV和GDI+批量调整图片大小并转换格式的方法,特别是从JPG到BMP再到JPG的过程。通过示例代码展示了如何读取、缩放和保存图片,适用于网络传输等场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

因为最近涉及将大的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头文件

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. #include < Gdiplus.h>  
  2. #pragma comment(lib, "Gdiplus.lib")  
  3. using namespace Gdiplus;  


[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. #include <Objbase.h>  
  2. #include <Objidl.h>  
  3. #pragma comment(lib, "Ole32.lib")  
  4. #pragma comment(lib, "Uuid.lib")  



2.定义两个公共函数:

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. INT GetEncoderClsid(const WCHAR *format, CLSID *pClsid)  
  2. {  
  3.     UINT  num = 0;          // number of image encoders      
  4.     UINT  size = 0;         // size of the image encoder array in bytes      
  5.   
  6.     ImageCodecInfo* pImageCodecInfo = NULL;  
  7.   
  8.     GetImageEncodersSize(&num, &size);  
  9.     if (size == 0){  
  10.         return -1;  // Failure     
  11.     }  
  12.   
  13.     pImageCodecInfo = (ImageCodecInfo*)(malloc(size));  
  14.     if (pImageCodecInfo == NULL){  
  15.         return -1;  // Failure     
  16.     }  
  17.   
  18.     GetImageEncoders(num, size, pImageCodecInfo);  
  19.   
  20.     for (UINT j = 0; j < num; ++j){  
  21.         if (wcscmp(pImageCodecInfo[j].MimeType, format) == 0){  
  22.             *pClsid = pImageCodecInfo[j].Clsid;  
  23.             free(pImageCodecInfo);  
  24.             return j;  // Success      
  25.         }  
  26.     }  
  27.   
  28.     free(pImageCodecInfo);  
  29.     return -1;  // Failure     
  30. }  

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转bmp
						wsprintf(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.youkuaiyun.com/detail/sz76211822/9819193
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值