代码涉及知识点:
1.DLL的创建。
2.函数传入参数,传出参数。
3.位图格式。
4.位图的位运算及格式转换。
5.文件操作。
6.DLL的调用
7.……
一、图片格式转换的DLL项目
//****************************
//**WinCeCppCamDll项目
//**本项目中引用了 开发板公司提供的摄像头驱动DLL文件一个
//****************************
1.1导入和引用DLL中的参数
EpcsCam.h
?
#pragma once
/* * 对应CAM_IOCTL_SAMSUNG_CAM_PR,打开RGB通道后,从uiRGB_Addr中获取视频图像数据,注意访问uiRGB_Addr时, * 必须采用内核模式(kernel mode),使用函数 SetKMode(TRUE),并在读取uiRGB_Addr后设置flag = 0, 如果有下 * 一帧数据来时,底层会将flag设为1,并设置uiRGB_Addr。这样方便读取每一帧数据 */ typedefstruct__PINGPONG_PR { unsignedint uiRGB_Addr; unsignedcharflag; /* 为1时候,视频数据有效 */ } PINGPONG_PR;
/* * 对应CAM_IOCTL_SAMSUNG_CAM,打开YUV通道后,从uiY_Addr, uiCb_Addr, uiCr_Addr中获取视频图像数据,注意访 * 问三个地址时,必须采用内核模式(kernel mode),使用函数 SetKMode(TRUE),并在读取地址数据后设置flag = 0, * 如果有下一帧数据来时,底层会将flag设为1,并设置YUV三个地址值。这样方便读取每一帧数据 */ typedefstructPINGPONG { unsignedintuiY_Addr; unsignedintuiCb_Addr; unsignedintuiCr_Addr; unsignedcharflag; } PINGPONG;
/* * 此结构体用于设置视频输出图像的大小,视频输出包含两个通道:RGB通道和YUV通道,其中RGB通道为RGB565数据 * 格式,视频预览的时候使用RGB通道 */ typedefstruct__IMAGE_SIZE { DWORDdwRGB_Width; /* RGB 通道的输出图像的宽度 */ DWORDdwRGB_Height; /* RGB 通道的输出图像的高度 */ DWORDdwYUV_Width; /* YUV 通道的输出图像的宽度 */ DWORDdwYUV_Height; /* YUV 通道的输出图像的高度 */ DWORDdwHorOffset; /* 视频源的水平剪切偏移 */ DWORDdwVerOffset; /* 视频源的垂直剪切偏移 */ } IMAGE_SIZE;
typedefBOOL(*pEpcCamCapture)(BOOLbIsRGB,BOOLbIsYUV); typedefBOOL(*pEpcCamPreviewOn)(DWORDdwXSize,DWORDdwYSize); typedefBOOL(*pEpcCamSetImage)(IMAGE_SIZE* pImageSize); typedefBOOL(*pEpcCamGetRgbFrame)(PINGPONG_PR *prAddInfo);
classEpcsCam { public: EpcsCam(void); public: ~EpcsCam(void);
public: HINSTANCEhDLL;//载入DLL的实例句柄 char*pBmpData;
public:
/********************************************************************************************************* ** Function name: epcCamCapture ** Descriptions: 本函数用于打开或者关闭Camera的视频捕获,如果bIsRGB和bIsYUV为FALSE即为关闭视频捕获, ** bIsRGB和bIsYUV其中任一个为TRUE,即为打开视频捕获 ** input parameters: bIsRGB 为TRUE时候打开RGB通道,为FALSE的时候关闭RGB通道 ** bIsYUV 为TRUE时候打开YUV通道,为FALSE的时候关闭YUV通道 ** output parameters: 无 ** Returned value: TRUE:成功;FALSE:失败 *********************************************************************************************************/
/********************************************************************************************************* ** Function name: epcCamPreviewOn ** Descriptions: 本函数用于启动预览图像,当启动视频捕获(打开RGB通道)后, 即可看到图像显示效果 ** 建议启动预览时,设置图像的分辨率小于显示屏的分辨率 ** 注意,有以下情况将操作失败:1、全屏模式下,2、RGB通道图像设置值大于360*288个象素 ** input parameters: dwXSize: 预览图像的X坐标(以LCD的左上角为原点,可以为负值) ** dwYSize: 预览图像的Y坐标(以LCD的左上角为原点,可以为负值) ** output parameters: 无 ** Returned value: TRUE:成功;FALSE:失败 *********************************************************************************************************/
/********************************************************************************************************* ** Function name: epcCamSetImage ** Descriptions: 本函数用于设置Camera输出图像的大小, 包含RGB通道和YUV通道的视频输出大小 ** 打开该接口驱动后,RGB和YUV图像大小默认为320*240 ** 注意,有以下情况将操作失败:1、正在视频捕获,2、打开预览,3,正在全屏模式 ** input parameters: pImageSize: 用于设置两个通道的视频输出大小 ** output parameters: 无 ** Returned value: TRUE:成功;FALSE:失败 *********************************************************************************************************/
/********************************************************************************************************* ** Function name: epcCamGetRgbFrame ** Descriptions: 本函数用于获取RGB通道的图像的数据缓存区地址 ** input parameters: prAddInfo 存放获取的地址,注意访问该地址的图像数据时候使用SetKMode(TRUE) ** output parameters: 无 ** Returned value: TRUE:成功;FALSE:失败 *********************************************************************************************************/
BOOLepcCamCapture (BOOLbIsRGB,BOOLbIsYUV); BOOLepcCamPreviewOn (DWORDdwXSize,DWORDdwYSize); BOOLepcCamSetImage (IMAGE_SIZE* pImageSize); BOOLepcCamGetRgbFrame (PINGPONG_PR *prAddInfo);
}; |
EpcsCam.cpp
?
#include "StdAfx.h" #include "EpcsCam.h"
/********************************************************************************************************* ** Function name: epcCamCapture ** Descriptions: 本函数用于打开或者关闭Camera的视频捕获,如果bIsRGB和bIsYUV为FALSE即为关闭视频捕获, ** bIsRGB和bIsYUV其中任一个为TRUE,即为打开视频捕获 ** input parameters: bIsRGB 为TRUE时候打开RGB通道,为FALSE的时候关闭RGB通道 ** bIsYUV 为TRUE时候打开YUV通道,为FALSE的时候关闭YUV通道 ** output parameters: 无 ** Returned value: TRUE:成功;FALSE:失败 *********************************************************************************************************/
/********************************************************************************************************* ** Function name: epcCamPreviewOn ** Descriptions: 本函数用于启动预览图像,当启动视频捕获(打开RGB通道)后, 即可看到图像显示效果 ** 建议启动预览时,设置图像的分辨率小于显示屏的分辨率 ** 注意,有以下情况将操作失败:1、全屏模式下,2、RGB通道图像设置值大于360*288个象素 ** input parameters: dwXSize: 预览图像的X坐标(以LCD的左上角为原点,可以为负值) ** dwYSize: 预览图像的Y坐标(以LCD的左上角为原点,可以为负值) ** output parameters: 无 ** Returned value: TRUE:成功;FALSE:失败 *********************************************************************************************************/
/********************************************************************************************************* ** Function name: epcCamSetImage ** Descriptions: 本函数用于设置Camera输出图像的大小, 包含RGB通道和YUV通道的视频输出大小 ** 打开该接口驱动后,RGB和YUV图像大小默认为320*240 ** 注意,有以下情况将操作失败:1、正在视频捕获,2、打开预览,3,正在全屏模式 ** input parameters: pImageSize: 用于设置两个通道的视频输出大小 ** output parameters: 无 ** Returned value: TRUE:成功;FALSE:失败 *********************************************************************************************************/
/********************************************************************************************************* ** Function name: epcCamGetRgbFrame ** Descriptions: 本函数用于获取RGB通道的图像的数据缓存区地址 ** input parameters: prAddInfo 存放获取的地址,注意访问该地址的图像数据时候使用SetKMode(TRUE) ** output parameters: 无 ** Returned value: TRUE:成功;FALSE:失败 *********************************************************************************************************/
EpcsCam::EpcsCam(void) { hDLL=LoadLibrary(CString("\\FlashDisk2\\epcCameraLib.dll"));//加载动态链接库MyDll.dll文件;
}
EpcsCam::~EpcsCam(void) { FreeLibrary(hDLL);//卸载MyDll.dll文件; }
BOOLEpcsCam::epcCamCapture (BOOLbIsRGB,BOOLbIsYUV) { BOOLbCaptureSucced=FALSE; pEpcCamCapture epcCamCapture =NULL; epcCamCapture=(pEpcCamCapture)GetProcAddress(hDLL,CString("epcCamCapture")); if(epcCamCapture) { bCaptureSucced=epcCamCapture(bIsRGB,bIsYUV); } returnbCaptureSucced; }
BOOLEpcsCam::epcCamPreviewOn (DWORDdwXSize,DWORDdwYSize) { BOOLbPreviewOnSucced=FALSE; pEpcCamPreviewOn epcCamPreviewOn =NULL; epcCamPreviewOn=(pEpcCamPreviewOn)GetProcAddress(hDLL,CString("epcCamPreviewOn")); if(epcCamPreviewOn) { bPreviewOnSucced=epcCamPreviewOn(dwXSize,dwYSize); } returnbPreviewOnSucced; }
BOOLEpcsCam::epcCamSetImage (IMAGE_SIZE* pImageSize) { BOOLbSetImageSucced=FALSE; pEpcCamSetImage epcCamSetImage =NULL; epcCamSetImage=(pEpcCamSetImage)GetProcAddress(hDLL,CString("epcCamSetImage")); if(epcCamSetImage) { bSetImageSucced=epcCamSetImage(pImageSize); } returnbSetImageSucced; }
BOOLEpcsCam::epcCamGetRgbFrame (PINGPONG_PR *prAddInfo) { BOOLbetRgbFrameSucced=FALSE; pEpcCamGetRgbFrame epcCamGetRgbFrame =NULL; epcCamGetRgbFrame=(pEpcCamGetRgbFrame)GetProcAddress(hDLL,CString("epcCamGetRgbFrame")); if(epcCamGetRgbFrame) { betRgbFrameSucced=epcCamGetRgbFrame(prAddInfo); } returnbetRgbFrameSucced; } |
1.2保存位图和保存异常日志等文件操作
FileOperate.h
?
#pragma once
classFileOperate { public: FileOperate(void); ~FileOperate(void);
public: staticvoidWriteLogMsg(charchLogMsg[]); staticCString GetTimeTag();
#if 1
staticvoidWriteBin(charchBin[]); //根据数据保存图片 staticBOOLbmpSaveImage (PTSTRpstrFileName, BITMAPFILEHEADER * pbmfh);
// 保存位图 staticvoidSaveBitMap(void); staticCString SaveBmp(char*pcBmpData,char*bmpFileData); staticCString SaveBmp0(BYTE*pcBmpData);//C++调用的函数
#endif
public: staticvoidImageConvertDemo( BYTE*pInBmp565Data,//输入的RGB565位图的数据实体部分(不包括文件头等信息) DWORDdwBitMapDataSize,//位图数据实体长度(不包括文件头等信息) BYTE**ppOutMallocData,//传出的JPG图片数据实体的指针 DWORD* pdwOutJpegMemSize,//传出的JPG图片数据的大小 int* pState//状态码:记录在执行此函数的过程中可能出现的问题 //char *bmpFileData );
}; |
FileOperate.cpp
?
#include "StdAfx.h" #include "FileOperate.h"
//#include "epccameralib.h"
#include "initguid.h "//如果不引用此头文件,就会出现 无法解析外部符号的错误 #include "IImageDemo.h"//图片转码测试
FileOperate::FileOperate(void) { }
FileOperate::~FileOperate(void) { }
voidFileOperate::WriteLogMsg(charchLogMsg[]) { charstrFilePath[40] ="\\FlashDisk2\\Log\\";//如果是"\\Log\\"则到了当前盘符的根目录下了。 charstrTimeFileName[20];//将当前时间转换成字符串---声明字符串长度的时候,要比实际长度多1,作为结尾符号
SYSTEMTIME sysTime; GetLocalTime( &sysTime );//得到系统时间
//sprintf(strTimeFileName,"%d-%d-%d",sysTime.wYear,sysTime.wMonth,sysTime.wDay);//"2010-09-21"
strcpy(strTimeFileName,"ErrorLog"); strcat(strTimeFileName,".txt");//加上扩展名--登录日志 strcat(strFilePath,strTimeFileName);//得到完整的路径名
FILE*fp;//文件指针
if((fp=fopen(strFilePath,"a"))==NULL)//以追加的形式往文件中写东西 { //如果打开不成功,则一般表示没有Log目录 //创建Log目录,然后再重新打开--一般情况下,如果目录存在的话,就不会创建成功的。 if(!CreateDirectory(_T("\\FlashDisk2\\Log"),NULL)) {//创建目录失败 //printf("Create Directory failed!\n"); return; }else { //printf("Create Directory succeed!\n");//cout << "OK" <<endl;
if((fp=fopen(strFilePath,"a"))==NULL)//以追加的形式往文本文件中写东西 { //printf("Open Failed\n"); //exit(0); return; } } }
charstrTimeTag[30];//="2010-09-21"; //将时间转成字符串 sprintf(strTimeTag,"%d-%d-%d %d:%d:%d ",sysTime.wYear,sysTime.wMonth,sysTime.wDay, sysTime.wHour,sysTime.wMinute,sysTime.wSecond);//"2010-09-21"
//strftime(chTimeTag, sizeof(chTimeTag), "%Y/%m/%d %X",&tim);//年月日时间字符串--作为登录日志中信息的时间标记头
fputs(strTimeTag,fp);//写入时间标记 fputs("# ",fp);//分隔符号 fputs(chLogMsg,fp);//写入消息日志 fputs("\n",fp);//换行
inti=fclose(fp);
if(i==0) { //printf("succeed!\n"); }else { //printf("fail!\n"); } }
CString FileOperate::GetTimeTag() {
CString strTimetag;
SYSTEMTIME sysTime; GetLocalTime( &sysTime );//得到系统时间
strTimetag.Format(_T("%d%d%d-%d%d%d"),sysTime.wYear,sysTime.wMonth,sysTime.wDay,sysTime.wHour,sysTime.wMinute,sysTime.wSecond); //sprintf(strTimeFileName,"%d-%d-%d",sysTime.wYear,sysTime.wMonth,sysTime.wDay);//"2010-09-21" returnstrTimetag;
}
#if 1
voidFileOperate::WriteBin(charchBin[]) { charstrFilePath[40] ="\\FlashDisk2\\Bins\\";//如果是"\\Log\\"则到了当前盘符的根目录下了。 charstrTimeFileName[20];//将当前时间转换成字符串---声明字符串长度的时候,要比实际长度多1,作为结尾符号
SYSTEMTIME sysTime; GetLocalTime( &sysTime );//得到系统时间 //sprintf(strTimeFileName,"%d-%d-%d",sysTime.wYear,sysTime.wMonth,sysTime.wDay);//"2010-09-21"
sprintf(strTimeFileName,"%d%d%d-%d%d%d",sysTime.wYear,sysTime.wMonth,sysTime.wDay, sysTime.wHour,sysTime.wMinute,sysTime.wSecond);//"2010-09-21"
strcat(strTimeFileName,".bins");//加上扩展名--登录日志 strcat(strFilePath,strTimeFileName);//得到完整的路径名
FILE*fp;//文件指针
if((fp=fopen(strFilePath,"wb+"))==NULL)//以追加的形式往二进制文件中写东西 { //如果打开不成功,则一般表示没有Log目录 //创建Log目录,然后再重新打开--一般情况下,如果目录存在的话,就不会创建成功的。 if(!CreateDirectory(_T("\\FlashDisk2\\Bins"),NULL)) { printf("Create Directory failed!\n"); }else { printf("Create Directory succeed!\n");//cout << "OK" <<endl;
if((fp=fopen(strFilePath,"a"))==NULL)//以追加的形式往文件中写东西 { printf("Open Failed\n"); exit(0); } } }
charstrTimeTag[30];//="2010-09-21"; //将时间转成字符串 sprintf(strTimeTag,"%d-%d-%d %d:%d:%d ",sysTime.wYear,sysTime.wMonth,sysTime.wDay, sysTime.wHour,sysTime.wMinute,sysTime.wSecond);//"2010-09-21"
//strftime(chTimeTag, sizeof(chTimeTag), "%Y/%m/%d %X",&tim);//年月日时间字符串--作为登录日志中信息的时间标记头
//fputs(strTimeTag,fp);//写入时间标记 //fputs(" : ",fp);//分隔符号 //fputs(chLogMsg,fp);//写入消息日志 //fputs("\n",fp);//换行
fputs(chBin,fp); inti=fclose(fp);
if(i==0) { printf("succeed!\n"); }else { printf("fail!\n"); } }
// 保存位图--最原来的模型 voidFileOperate::SaveBitMap(void) { // TODO: Add your control notification handler code here IMAGE_SIZE tDispSize = {0}; DWORD dwPreMode; PINGPONG_PR DataAddr; BITMAPFILEHEADER *pFileHead = NULL; /* 位图文件的头指针 */ BITMAPINFO *pBmpInfo = NULL; /* 位图信息的指针 */ char *pcBmpData = NULL; /* 位图数据区的指针 */ DWORD dwImgeX; /* 位图水平像素 */ DWORD dwImgeY; /* 位图垂直像素 */
DWORD dwFileHeadSize =sizeof(BITMAPFILEHEADER); /* 位图文件的头区域大小 */ DWORD dwInfoSize =sizeof(BITMAPINFO) + 4 * 2; /* 位图文件的信息区大小 */ DWORD dwBipMapSize; /* 位图文件的数据区大小 */ CString cstrPathname;
cstrPathname="\\test.bmp";
dwImgeX = 320; dwImgeY = 240;
dwBipMapSize = 2 * dwImgeX * dwImgeY; /* 文件头指针指向整个位图的空间 320*240*2/1024 =150K*/ pFileHead = (BITMAPFILEHEADER*)malloc(dwFileHeadSize + dwInfoSize + dwBipMapSize); pBmpInfo = (BITMAPINFO *)malloc(dwInfoSize);
pFileHead->bfOffBits = dwFileHeadSize + dwInfoSize; /* 以下为填充位图的空间 */ pFileHead->bfSize = dwFileHeadSize + dwInfoSize + dwBipMapSize; pFileHead->bfType = 0x4D42;
pcBmpData = (char*) pFileHead + pFileHead->bfOffBits;
pBmpInfo->bmiHeader.biHeight = 0 - (signed)dwImgeY; pBmpInfo->bmiHeader.biWidth = dwImgeX ; pBmpInfo->bmiHeader.biBitCount = 16; pBmpInfo->bmiHeader.biClrImportant = 0; pBmpInfo->bmiHeader.biClrUsed = 0; pBmpInfo->bmiHeader.biCompression = BI_BITFIELDS; //pBmpInfo->bmiHeader.biCompression = BI_RGB; pBmpInfo->bmiHeader.biPlanes = 1; pBmpInfo->bmiHeader.biSize =sizeof(BITMAPINFOHEADER); pBmpInfo->bmiHeader.biSizeImage = dwBipMapSize;
pBmpInfo->bmiColors[0].rgbBlue = 0x00; pBmpInfo->bmiColors[0].rgbGreen = 0xF8; pBmpInfo->bmiColors[0].rgbRed = 0x00; pBmpInfo->bmiColors[0].rgbReserved = 0x00; pBmpInfo->bmiColors[1].rgbBlue = 0xE0; pBmpInfo->bmiColors[1].rgbGreen = 0x07; pBmpInfo->bmiColors[1].rgbRed = 0x00; pBmpInfo->bmiColors[1].rgbReserved = 0x00; pBmpInfo->bmiColors[2].rgbBlue = 0x1F; pBmpInfo->bmiColors[2].rgbGreen = 0x00; pBmpInfo->bmiColors[2].rgbRed = 0x00; pBmpInfo->bmiColors[2].rgbReserved = 0x00;
memcpy((void*)(pFileHead + 1), (void*)pBmpInfo, dwInfoSize);
//最后将RGB565的图片数据全部COPY到pcBmpData中了----这里可以通过读文件的形式将这些数据读上来。!!!!!! //只需要在此处将那个RGB565的文件用二进制的格式读进来就OK了!!! CFile hFile; hFile.Open(_T("\\2010-9-23.bins"),CFile::modeRead); hFile.Read(pcBmpData,dwBipMapSize);
bmpSaveImage((PTSTR)cstrPathname.GetBuffer(0), pFileHead); /* 保存成BMP图片 */ cstrPathname.ReleaseBuffer();
free(pFileHead); free(pBmpInfo); hFile.Close();//关闭文件
}
//带参数的保存位图函数 BOOLFileOperate::bmpSaveImage(PTSTRpstrFileName, BITMAPFILEHEADER *pbmfh) { BOOL bSuccess ; DWORD dwBytesWritten ; HANDLEhFile;
hFile = CreateFile ( pstrFileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL) ;
if(hFile == INVALID_HANDLE_VALUE) { returnFALSE ; }
bSuccess = WriteFile (hFile, pbmfh, pbmfh->bfSize, &dwBytesWritten, NULL);
CloseHandle (hFile) ;
if(!bSuccess || (dwBytesWritten != pbmfh->bfSize)) { DeleteFile (pstrFileName) ; returnFALSE ; } returnTRUE ; }
//************************************ // Method: SaveBmp // FullName: FileOperate::SaveBmp // Access: public static // Returns: CString 位图的名称 // Qualifier: 保存位图 // Parameter: char * pcBmpDataTemp 位图数据区内容 //************************************ CString FileOperate::SaveBmp0(BYTE*pcBmpDataTemp) { // TODO: Add your control notification handler code here IMAGE_SIZE tDispSize = {0}; DWORD dwPreMode; PINGPONG_PR DataAddr; BITMAPFILEHEADER *pFileHead = NULL; /* 位图文件的头指针 */ BITMAPINFO *pBmpInfo = NULL; /* 位图信息的指针 */ char *pcBmpData = NULL; /* 位图数据区的指针 */ DWORD dwImgeX; /* 位图水平像素 */ DWORD dwImgeY; /* 位图垂直像素 */
DWORD dwFileHeadSize =sizeof(BITMAPFILEHEADER); /* 位图文件的头区域大小 */ DWORD dwInfoSize =sizeof(BITMAPINFO) + 4 * 2; /* 位图文件的信息区大小 */ DWORD dwBipMapSize; /* 位图文件的数据区大小 */ CString cstrPathname;
cstrPathname+="\\FlashDisk2\\bmp\\"; cstrPathname+=GetTimeTag(); cstrPathname+=".bmp"; dwImgeX = 320; dwImgeY = 240;
dwBipMapSize = 2 * dwImgeX * dwImgeY; /* 文件头指针指向整个位图的空间 320*240*2/1024 =150K*/ pFileHead = (BITMAPFILEHEADER*)malloc(dwFileHeadSize + dwInfoSize + dwBipMapSize); pBmpInfo = (BITMAPINFO *)malloc(dwInfoSize);
pFileHead->bfOffBits = dwFileHeadSize + dwInfoSize; /* 以下为填充位图的空间 */ pFileHead->bfSize = dwFileHeadSize + dwInfoSize + dwBipMapSize; pFileHead->bfType = 0x4D42;
pcBmpData = (char*) pFileHead + pFileHead->bfOffBits;
pBmpInfo->bmiHeader.biHeight = 0 - (signed)dwImgeY; pBmpInfo->bmiHeader.biWidth = dwImgeX ; pBmpInfo->bmiHeader.biBitCount = 16; pBmpInfo->bmiHeader.biClrImportant = 0; pBmpInfo->bmiHeader.biClrUsed = 0; pBmpInfo->bmiHeader.biCompression = BI_BITFIELDS; pBmpInfo->bmiHeader.biPlanes = 1; pBmpInfo->bmiHeader.biSize =sizeof(BITMAPINFOHEADER); pBmpInfo->bmiHeader.biSizeImage = dwBipMapSize;
pBmpInfo->bmiColors[0].rgbBlue = 0x00; pBmpInfo->bmiColors[0].rgbGreen = 0xF8; pBmpInfo->bmiColors[0].rgbRed = 0x00; pBmpInfo->bmiColors[0].rgbReserved = 0x00; pBmpInfo->bmiColors[1].rgbBlue = 0xE0; pBmpInfo->bmiColors[1].rgbGreen = 0x07; pBmpInfo->bmiColors[1].rgbRed = 0x00; pBmpInfo->bmiColors[1].rgbReserved = 0x00; pBmpInfo->bmiColors[2].rgbBlue = 0x1F; pBmpInfo->bmiColors[2].rgbGreen = 0x00; pBmpInfo->bmiColors[2].rgbRed = 0x00; pBmpInfo->bmiColors[2].rgbReserved = 0x00;
memcpy((void*)(pFileHead + 1), (void*)pBmpInfo, dwInfoSize);
//最后将RGB565的图片数据全部COPY到pcBmpData中了----这里可以通过读文件的形式将这些数据读上来。!!!!!! //只需要在此处将那个RGB565的文件用二进制的格式读进来就OK了!!! /*CFile hFile; hFile.Open(_T("\\2010-9-23.bins"),CFile::modeRead); hFile.Read(pcBmpData,dwBipMapSize);*/ memcpy(pcBmpData,pcBmpDataTemp,dwBipMapSize);//将图片数据区值COPY过来
// memcpy(bmpFileData,pFileHead,153666);//当程序运行到此处,C#程序中的临时数组已经有值了。
bmpSaveImage((PTSTR)cstrPathname.GetBuffer(0), pFileHead); /* 保存成BMP图片 */ cstrPathname.ReleaseBuffer();
free(pFileHead); free(pBmpInfo);
returncstrPathname; }
//************************************ // Method: SaveBmp // FullName: FileOperate::SaveBmp // Access: public static // Returns: CString 位图的名称 // Qualifier: 保存位图 // Parameter: char * pcBmpDataTemp 位图数据区内容 //************************************ CString FileOperate::SaveBmp(char*pcBmpDataTemp,char*bmpFileData) { // TODO: Add your control notification handler code here IMAGE_SIZE tDispSize = {0}; DWORD dwPreMode; PINGPONG_PR DataAddr; BITMAPFILEHEADER *pFileHead = NULL; /* 位图文件的头指针 */ BITMAPINFO *pBmpInfo = NULL; /* 位图信息的指针 */ char *pcBmpData = NULL; /* 位图数据区的指针 */ DWORD dwImgeX; /* 位图水平像素 */ DWORD dwImgeY; /* 位图垂直像素 */
DWORD dwFileHeadSize =sizeof(BITMAPFILEHEADER); /* 位图文件的头区域大小 */ DWORD dwInfoSize =sizeof(BITMAPINFO) + 4 * 2; /* 位图文件的信息区大小 */ DWORD dwBipMapSize; /* 位图文件的数据区大小 */ CString cstrPathname;
cstrPathname+="\\FlashDisk2\\bmp\\"; cstrPathname+=GetTimeTag(); cstrPathname+=".bmp"; dwImgeX = 320; dwImgeY = 240;
dwBipMapSize = 2 * dwImgeX * dwImgeY; /* 文件头指针指向整个位图的空间 320*240*2/1024 =150K*/ pFileHead = (BITMAPFILEHEADER*)malloc(dwFileHeadSize + dwInfoSize + dwBipMapSize); pBmpInfo = (BITMAPINFO *)malloc(dwInfoSize);
pFileHead->bfOffBits = dwFileHeadSize + dwInfoSize; /* 以下为填充位图的空间 */ pFileHead->bfSize = dwFileHeadSize + dwInfoSize + dwBipMapSize; pFileHead->bfType = 0x4D42;
pcBmpData = (char*) pFileHead + pFileHead->bfOffBits;
pBmpInfo->bmiHeader.biHeight = 0 - (signed)dwImgeY; pBmpInfo->bmiHeader.biWidth = dwImgeX ; pBmpInfo->bmiHeader.biBitCount = 16; pBmpInfo->bmiHeader.biClrImportant = 0; pBmpInfo->bmiHeader.biClrUsed = 0; pBmpInfo->bmiHeader.biCompression = BI_BITFIELDS; pBmpInfo->bmiHeader.biPlanes = 1; pBmpInfo->bmiHeader.biSize =sizeof(BITMAPINFOHEADER); pBmpInfo->bmiHeader.biSizeImage = dwBipMapSize;
pBmpInfo->bmiColors[0].rgbBlue = 0x00; pBmpInfo->bmiColors[0].rgbGreen = 0xF8; pBmpInfo->bmiColors[0].rgbRed = 0x00; pBmpInfo->bmiColors[0].rgbReserved = 0x00; pBmpInfo->bmiColors[1].rgbBlue = 0xE0; pBmpInfo->bmiColors[1].rgbGreen = 0x07; pBmpInfo->bmiColors[1].rgbRed = 0x00; pBmpInfo->bmiColors[1].rgbReserved = 0x00; pBmpInfo->bmiColors[2].rgbBlue = 0x1F; pBmpInfo->bmiColors[2].rgbGreen = 0x00; pBmpInfo->bmiColors[2].rgbRed = 0x00; pBmpInfo->bmiColors[2].rgbReserved = 0x00;
memcpy((void*)(pFileHead + 1), (void*)pBmpInfo, dwInfoSize);
//最后将RGB565的图片数据全部COPY到pcBmpData中了----这里可以通过读文件的形式将这些数据读上来。!!!!!! //只需要在此处将那个RGB565的文件用二进制的格式读进来就OK了!!! /*CFile hFile; hFile.Open(_T("\\2010-9-23.bins"),CFile::modeRead); hFile.Read(pcBmpData,dwBipMapSize);*/ memcpy(pcBmpData,pcBmpDataTemp,dwBipMapSize);//将图片数据区值COPY过来
memcpy(bmpFileData,pFileHead,153666);//当程序运行到此处,C#程序中的临时数组已经有值了。
bmpSaveImage((PTSTR)cstrPathname.GetBuffer(0), pFileHead); /* 保存成BMP图片 */ cstrPathname.ReleaseBuffer();
free(pFileHead); free(pBmpInfo);
returncstrPathname; }
#endif
//pcBmpDataTemp--从摄像头中得到的565数据区内容 voidFileOperate::ImageConvertDemo(BYTE*pInBmp565Data,//输入的RGB565位图的数据实体部分--不包括位图文件等信息 DWORDdwBitMapDataSize,//位图数据实体长度(不包括文件头等信息)153600 BYTE**ppOutMallocData,//传出的JPG图片数据实体 DWORD* pdwOutJpegMemSize,//传出的JPG图片数据的大小 int* pState//状态码:记录在执行此函数的过程中可能出现的问题 ) {
BYTE* pOutRgb555BmpData=NULL;//输出的555格式的位图数据实体 DWORDdwRgb555BmpFileDataLength=0;//153666;//暂时先赋一个值,最终还是要通过传递得到的----######
dwRgb555BmpFileDataLength=sizeof(BITMAPFILEHEADER)//位图文件信息头:14 +sizeof(BITMAPINFOHEADER)//位图信息头:40 + 3*sizeof(RGBQUAD)//RGB掩码:12 + dwBitMapDataSize;//数据实体部分:153600
IImageDemo imgDemo;
//FileOperate::SaveBmp0(pInBmp565Data);//测试代码:此处测试表明,可以取得到实时的数据了 imgDemo.ConvertBmpRgb565To555(pInBmp565Data,dwRgb555BmpFileDataLength,&pOutRgb555BmpData);//测试转码
BYTE* pJpegData=NULL; DWORDdwpJpegDataLength;//Jpeg数组的长度 imgDemo.ConvertRgb555BmpToJpgInMem(pOutRgb555BmpData,dwRgb555BmpFileDataLength,&pJpegData,&dwpJpegDataLength);//因为是在函数内部动态分配的内存,所以需要用指针的指针
//传出数据 *pdwOutJpegMemSize=dwpJpegDataLength;//传出长度---在最终代码中要简化 *ppOutMallocData=pJpegData;
} |
1.3转换图片格式
GetImage.h
?
#pragma once
#include "initguid.h "//如果不引用此头文件,就会出现 无法解析外部符号的错误 #include "imaging.h"//图片转码测试
classGetImage { public: GetImage(DWORDdwRGB_Width,DWORDdwRGB_Height); GetImage(void); ~GetImage(void);
public: DWORDdwRGB_Width; /* RGB 通道的输出图像的宽度 */ DWORDdwRGB_Height; /* RGB 通道的输出图像的高度 */
public: //转换图片格式,并得到jpeg文件的数组 voidGetJpegBytes( BYTE*pInBmp565Data,//输入的RGB565位图的数据实体部分(不包括文件头等信息) DWORDdwBitMapDataSize,//位图数据实体长度(不包括文件头等信息) BYTE**ppOutMallocData,//传出的JPG图片数据实体的指针 DWORD* pdwOutJpegMemSize,//传出的JPG图片数据的大小 int* pState//状态码:记录在执行此函数的过程中可能出现的问题 );
private:
//将Rgb565编码格式的位图转成Rgb555的位图 voidConvertBmpRgb565To555( BYTE* pInRgb565BmpData,//输入的565格式的位图数据实体 DWORDdwRgb555BmpFileDataLength,//位图文件大小 BYTE** ppOutRgb555BmpData//输出的555格式的位图数据实体 );
//将数组转换到IStream中 voidCopyByteArrayToISream( BYTE*pInByteArray,//输入的字节数组 DWORDdwArrayLength,//字节数组的长度 IStream **ppOutIStream//传出的由字节转换的流 );
/* *函数介绍:根据编码器类型名称,得到指定的编码器CLSID *入口参数:pImagingFactory: Image工厂接口对象 wszMimeType : Image编码格式名称 *出口参数:pclsid :编码器的CLSID *返回值:TRUE : 成功; FALSE: 失败 */ BOOLGetEnCodecCLSID(IImagingFactory * pImagingFactory,WCHAR* wszMimeType , CLSID * pclsid);
//Rgb555编码的BMP位图转JPG--在内存中进行 voidConvertRgb555BmpToJpgInMem( BYTE* pInRgb555BmpFileData,//输入的RGB555位图文件流--包括位图数据实体及文件和位图信息 DWORDdwRgb555BmpFileDataLength,//RGB555位图文件流的长度 BYTE** ppOutJpegData,//输出的JPG位图文件数据流 DWORD* dwpOutJpegDataLegth//转码后的JPG位图大小 );
}; |
GetImage.cpp
?
#include "StdAfx.h" #include "GetImage.h"
#include "CamException.h"
//#include "epccameralib.h"//摄像头驱动
GetImage::GetImage(void) { }
GetImage::GetImage(DWORDdwWidth,DWORDdwHeight) { dwRGB_Height=dwHeight; dwRGB_Width=dwWidth; }
GetImage::~GetImage(void) { }
voidGetImage::GetJpegBytes( BYTE*pInBmp565Data,//输入的RGB565位图的数据实体部分--不包括位图文件等信息 DWORDdwBitMapDataSize,//位图数据实体长度(不包括文件头等信息)153600 BYTE**ppOutMallocData,//传出的JPG图片数据实体 DWORD* pdwOutJpegMemSize,//传出的JPG图片数据的大小 int* pState//状态码:记录在执行此函数的过程中可能出现的问题 ) {
try { BYTE* pOutRgb555BmpData=NULL;//输出的555格式的位图数据实体 DWORDdwRgb555BmpFileDataLength=0;//位图文件长度153666
dwRgb555BmpFileDataLength=sizeof(BITMAPFILEHEADER)//位图文件信息头:14 +sizeof(BITMAPINFOHEADER)//位图信息头:40 + 3*sizeof(RGBQUAD)//RGB掩码:12 + dwBitMapDataSize;//数据实体部分:153600
//将位图数据转码成555数据,并加上相关文件头,最后形成555位图文件 ConvertBmpRgb565To555(pInBmp565Data,dwRgb555BmpFileDataLength,&pOutRgb555BmpData);
#pragma region //测试没有取到图片的情况
//CFile hSaveFile; //hSaveFile.Open(L"\\565bmp.bin",CFile::modeCreate | CFile::modeWrite |CFile::modeNoTruncate); ////创立一个txt文件。 //hSaveFile.SeekToEnd(); //文件末尾
//hSaveFile.Write(pInBmp565Data,dwBitMapDataSize); //hSaveFile.Close();
#pragma endregion
if(pOutRgb555BmpData==NULL) { throwCString("ConvertBmpRgb565To555位图图片格式转码失败"); }
BYTE* pJpegData=NULL; DWORDdwpJpegDataLength;//Jpeg数组的长度 ConvertRgb555BmpToJpgInMem(pOutRgb555BmpData,dwRgb555BmpFileDataLength,&pJpegData,&dwpJpegDataLength); //因为是在函数内部动态分配的内存,所以需要用指针的指针
if(pOutRgb555BmpData!=NULL) { free(pOutRgb555BmpData);//555位图数据使用完毕后,就释放 pOutRgb555BmpData=NULL; }
if(pJpegData==NULL) { throwCString("ConvertRgb555BmpToJpgInMem位图压缩失败"); }
//传出数据 *pdwOutJpegMemSize=dwpJpegDataLength;//传出长度---在最终代码中要简化 *ppOutMallocData=pJpegData; } catch(CString exMsg) { exMsg=L"GetJpegBytes(BYTE*,DWORD,BYTE**,DWORD*,int*):"+ exMsg; CamException::WriteToFile(exMsg); } catch(CException* e) { TCHARszCause[255]; e->GetErrorMessage(szCause, 255); CString exMsg=CString(szCause); exMsg=L"GetJpegBytes(BYTE*,DWORD,BYTE**,DWORD*,int*):"+ exMsg; CamException::WriteToFile(exMsg); }
}
//将Rgb565编码格式的位图转成Rgb555的位图---位图的大小不会变化,只是数据的编码方式发生变化 voidGetImage::ConvertBmpRgb565To555( BYTE* pInRgb565BmpData,//输入的565格式的位图数据实体----不包括位图文件信息 DWORDdwRgb555BmpFileDataLength,//位图文件大小153666 BYTE** ppOutRgb555BmpFileData//输出的555格式的位图文件数据流--可以形成完整文件 ) {
try { #pragma region //设置位图文件 BITMAPFILEHEADER *pFileHead = NULL; /* 位图文件的头指针 */ BITMAPINFO *pBmpInfo = NULL; /* 位图信息的指针 */ char *pcBmpData = NULL; /* 位图数据区的指针 */ DWORD dwImgeX; /* 位图水平像素 */ DWORD dwImgeY; /* 位图垂直像素 */
DWORD dwFileHeadSize =sizeof(BITMAPFILEHEADER); /* 位图文件的头区域大小 */ DWORD dwInfoSize =sizeof(BITMAPINFO) + 4 * 2; /* 位图文件的信息区大小 */ DWORD dwBipMapSize; /* 位图文件的数据区大小 */
dwBipMapSize = 2 * dwRGB_Height * dwRGB_Width;//文件头指针指向整个位图的空间 320*240*2/1024 =150K pFileHead = (BITMAPFILEHEADER*)malloc(dwFileHeadSize + dwInfoSize + dwBipMapSize); if(pFileHead==NULL) { throwCString("pFileHead位图信息头内存分配失败"); }
pBmpInfo = (BITMAPINFO *)malloc(dwInfoSize);
if(pBmpInfo==NULL) { free(pFileHead); pFileHead==NULL;//释放已经申请到的内存 throwCString("pBmpInfo位图信息头内存分配失败"); }
pFileHead->bfOffBits = dwFileHeadSize + dwInfoSize; /* 以下为填充位图的空间 */ pFileHead->bfSize = dwFileHeadSize + dwInfoSize + dwBipMapSize; pFileHead->bfType = 0x4D42;//位图文件的 类型代码
pcBmpData = (char*) pFileHead + pFileHead->bfOffBits;
pBmpInfo->bmiHeader.biHeight = 0 - (signed)dwRGB_Height; pBmpInfo->bmiHeader.biWidth = dwRGB_Width ;
pBmpInfo->bmiHeader.biBitCount = 16; pBmpInfo->bmiHeader.biClrImportant = 0; pBmpInfo->bmiHeader.biClrUsed = 0; //pBmpInfo->bmiHeader.biCompression = BI_BITFIELDS;//RGB565格式 pBmpInfo->bmiHeader.biCompression = BI_RGB;//RGB555格式 pBmpInfo->bmiHeader.biPlanes = 1; pBmpInfo->bmiHeader.biSize =sizeof(BITMAPINFOHEADER); pBmpInfo->bmiHeader.biSizeImage = dwBipMapSize;
memcpy((void*)(pFileHead + 1), (void*)pBmpInfo, dwInfoSize); memcpy(pcBmpData,pInRgb565BmpData,dwBipMapSize);//将摄像头数据复制到位图文件内存缓冲区中
#pragma endregion
#pragma region //进行颜色分量提取,并转码成RGB555
char* p555Data=NULL; p555Data=(char*)malloc(dwBipMapSize);//申请一片数据作为555数据的缓冲区
if(p555Data==NULL) { free(pFileHead); pFileHead=NULL; free(pBmpInfo); pBmpInfo=NULL; throwCString("p555Data内存分配失败"); }
DWORDwidth=dwRGB_Width;//320 DWORDheight=dwRGB_Height;//240 intpitch=width+width%2;//偏移量
for(inti=0;i<height;i++)//图片的高度是240 { for(intj=0;j<width;j++) {
//分解出RGB三分量---RGB565的 UCHARb=pcBmpData[(i*pitch+j)*2]&0x1F; UCHARg=((((pcBmpData[(i*pitch+j)*2+1]<<5)&0xFF)>>2) & 0x38) +((pcBmpData[(i*pitch+j)*2]>>5)&0x07); UCHARr=(pcBmpData[(i*pitch+j)*2+1]>>3)&0x1F;
g=g/2;//把g分量从RGB565标准转码成RGB555标准
//将新的RGB分量弄到RGB555的图片数据区中. p555Data[(i*pitch+j)*2] = ((g<<5)&0xE0)+b;//gb分量 p555Data[(i*pitch+j)*2+1] = (r<<2)+(g/8);//rg分量
} }
memcpy(pcBmpData,p555Data,dwBipMapSize);//将新的数据区内容复制到原来的数据区中进行了数据覆盖
#pragma endregion
//---*****传出参数 *ppOutRgb555BmpFileData=(BYTE*)malloc(dwRgb555BmpFileDataLength); if(*ppOutRgb555BmpFileData==NULL) { free(pFileHead); pFileHead=NULL; free(pBmpInfo); pBmpInfo=NULL; free(p555Data); p555Data=NULL; throwCString("*ppOutRgb555BmpFileData内存分配失败"); } memcpy(*ppOutRgb555BmpFileData,pFileHead,dwRgb555BmpFileDataLength);
free(pFileHead); free(pBmpInfo); free(p555Data); } catch(CString exMsg) { exMsg=L"ConvertBmpRgb565To555(BYTE*,DWORD,BYTE**):"+ exMsg; CamException::WriteToFile(exMsg); } catch(CException* e) { TCHARszCause[255]; e->GetErrorMessage(szCause, 255); CString exMsg=CString(szCause); exMsg=L"ConvertBmpRgb565To555(BYTE*,DWORD,BYTE**):"+ exMsg; CamException::WriteToFile(exMsg); }
}
// //Rgb555编码的BMP位图转JPG--在内存中进行 voidGetImage::ConvertRgb555BmpToJpgInMem( BYTE* pInRgb555BmpFileData,//输入的RGB555位图文件流--包括位图数据实体及文件和位图信息 DWORDdwRgb555BmpFileDataLength,//RGB555位图文件流的长度 BYTE** ppOutJpegData,//传出的JPG文件数据流 DWORD* dwpOutJpegDataLegth//JPG文件流大小 ) {
try { #pragma region HRESULThr;//保存每个步骤的中间结果,判断过程运行是否正确----到时候有必要写个异常日志记录 TCHAR*tszMime;//输出图片格式 tszMime = L"image/jpeg"; //指定转换后,图象文件的格式
IStream *pRgb555BmpStream = NULL;// 流接口对象---读取BMP文件,然后在内存中保存此文件数据 IStream * pJpegStream=NULL;//用来保存转换的JPG文件 IImagingFactory * pImagingFactory = NULL ;//Image工厂接口对象 IImageSink *pImageSink = NULL;//Image Sink接口对象 IImageDecoder *pImageDecoder = NULL; //解码器接口对象 IImageEncoder *pImageEncoder = NULL; //编码器接口对象 CLSID clsidEncoder; //编码器CLSID
//小技巧:有些变量虽然只在函数体里局部用到,但是因为是动态分配的内存,需要最后手动释放内存,最好放在最前面声明,防止最后遗忘了。 STATSTG * pIStreamState=NULL;//得到pJpegStream的状态 BYTE* pJpegData=NULL;//用来存储从文件流中剥出来的数据。
//初始化COM环境 if(FAILED(hr = CoInitializeEx(NULL, COINIT_MULTITHREADED))) { TRACE(L"COINIT_MULTITHREADED ERROR"); return; }
CopyByteArrayToISream(pInRgb555BmpFileData,dwRgb555BmpFileDataLength,&pRgb555BmpStream);//承接数据
//将流指针移到流起点。-----一般都要进行一下这样的测试 LARGE_INTEGER dlibMove0; dlibMove0.HighPart=0; dlibMove0.LowPart=0; pRgb555BmpStream->Seek(dlibMove0,STREAM_SEEK_SET,NULL);
//得到Image工厂接口对象---用指定的类标识符创建一个Com对象,用指定的类标识符创建一个未初始化的对象。 hr = CoCreateInstance(CLSID_ImagingFactory,//创建的Com对象的类标识符(CLSID) NULL,//指向接口IUnknown的指针 CLSCTX_INPROC_SERVER,//运行可执行代码的上下文 IID_IImagingFactory,//创建的Com对象的接口标识符 (void**) &pImagingFactory);//用来接收指向Com对象接口地址的指针变量
if(FAILED(hr)) { TRACE(L"IMAGE FACTORY CREATED ERROR"); gotofinish; }
//创建解码器接口 if(FAILED(hr = pImagingFactory->CreateImageDecoder(pRgb555BmpStream, DecoderInitFlagBuiltIn1st, &pImageDecoder))) { gotofinish; }
//根据编码器类型名称得到编码器CLSID if(!GetEnCodecCLSID(pImagingFactory,tszMime, &clsidEncoder ))//tszMime = L"image/jpeg"; //指定转换后,图象文件的格式 { gotofinish; }
if(FAILED(hr = CreateStreamOnHGlobal(NULL,TRUE,&pJpegStream)))//必需要和某个内存区域关联,或者进行一次实例化,比如用COleStreamFile { gotofinish; }
if(FAILED(hr = pImagingFactory->CreateImageEncoderToStream(&clsidEncoder, pJpegStream, &pImageEncoder))) { gotofinish; }
//得到编码器接口的sink对象。此ImageSink接口作为一个槽或者管道来理解; //是用于负责pImageEncoder和pImageDecoder之间的传输 if(FAILED(hr = pImageEncoder->GetEncodeSink(&pImageSink))) { gotofinish; } //开始解码 if(FAILED(hr = pImageDecoder->BeginDecode(pImageSink, NULL))) { gotofinish; } //循环解码,直到结束 for(;;)//for循环其实只运行了一个周期 { //解码 hr = pImageDecoder->Decode();//解码后,生成一个8K的文件 //继续解码后面的部分 if(E_PENDING == hr) { Sleep(500); }//失败 elseif(FAILED(hr)) { //终止解码 pImageDecoder->EndDecode(hr); gotofinish; } else { //解码成功 break; } }
pImageDecoder->EndDecode(hr);//结束解码 pImageSink->Release();//释放pImageSink对象 pImageSink = NULL; pImageEncoder->TerminateEncoder();//结束编码,此时就已经完成了文件格式的转换
#pragma region //从流中提取数据到BYTE数组中
DWORDdwStreamLengthLowPart;//状态中的长度分量--低位(因为实际图片数据不需要高位那么长) //得到pJpegStream的长度--然后提取出数据,保存到BYTE数组中 pIStreamState=(STATSTG *)malloc(sizeof(STATSTG));//如果不动态开辟空间,将无法传值进来。 if(NULL == pIStreamState)//如果申请内存没有成功 { CamException::WriteToFile(L"pIStreamState申请内存失败"); gotofinish; }
if(FAILED(hr=pJpegStream->Stat(pIStreamState,STATFLAG_NONAME))) { CamException::WriteToFile(L"pJpegStream获取状态失败"); gotofinish; } dwStreamLengthLowPart = pIStreamState->cbSize.LowPart;//取出流状态中的长度分量 free(pIStreamState); pIStreamState=NULL;//指针置空,防止野指针出现
pJpegData = (BYTE*)malloc(dwStreamLengthLowPart);//用来存储从文件流中剥出来的数据。 if(NULL == pJpegData)//如果申请内存没有成功 { gotofinish; }
//将流指针移到流起点。 LARGE_INTEGER dlibMove; dlibMove.HighPart=0; dlibMove.LowPart=0; pJpegStream->Seek(dlibMove,STREAM_SEEK_SET,NULL);
hr=pJpegStream->Read(pJpegData,dwStreamLengthLowPart,NULL);//将流文件内容放置到数据中 if(FAILED(hr)) { gotofinish; }
#pragma endregion
*ppOutJpegData=pJpegData;//将图片数据指针传递出去 *dwpOutJpegDataLegth = dwStreamLengthLowPart;//此处传值可能出了点小故障,明天就干脆把这两个参数封装到一个自定义的结构里面,然后动态生成吧。
finish:
//释放pRgb555BmpStream对象 if(pRgb555BmpStream) pRgb555BmpStream->Release(); if(pJpegStream) pJpegStream->Release();
//释放pImageSink对象 if(pImageSink) pImageSink->Release(); //释放pImageDecoder对象 if(pImageDecoder) pImageDecoder->Release(); //释放pImageEncoder对象 if(pImageEncoder) pImageEncoder->Release(); //释放IImagingFactory接口对象 if(pImagingFactory) pImagingFactory->Release(); //释放程序占用的COM资源 CoUninitialize(); #pragma endregion } catch(CString exMsg) { exMsg=L"ConvertBmpRgb565To555(BYTE*,DWORD,BYTE**):"+ exMsg; CamException::WriteToFile(exMsg); } catch(CException* e) { TCHARszCause[255]; e->GetErrorMessage(szCause, 255); CString exMsg=CString(szCause); exMsg=L"ConvertBmpRgb565To555(BYTE*,DWORD,BYTE**):"+ exMsg; CamException::WriteToFile(exMsg); }
}
voidGetImage::CopyByteArrayToISream( BYTE*pInByteArray,//输入的字节数组 DWORDdwArrayLength,//字节数组的长度 IStream **ppOutIStream//传出的由字节转换的流 ) { try { HRESULThrRet = S_FALSE; HGLOBALhg = NULL; BYTE* pbLocked = NULL;
//分配内存--此方法已经过时,现在一般都用malloc或者new了 hg = GlobalAlloc(GMEM_MOVEABLE, dwArrayLength); if(NULL == hg) { CamException::WriteToFile(L"hg分配内存失败"); gotoerror; } //得到已经分配的内存指针 pbLocked = (BYTE*) GlobalLock(hg); if(NULL == pbLocked) { CamException::WriteToFile(L"pbLocked获取指针失败"); gotoerror; }
memcpy(pbLocked,pInByteArray,dwArrayLength);//不从文件中读取,而是直接在内存地址区间进行复制 GlobalUnlock(hg);//解锁已经分配全局内存,对应GlobalLock(hg) hrRet = CreateStreamOnHGlobal(hg, TRUE, ppOutIStream);//创建Stream对象
return;
error://错误处理,并释放内存(没有出现错误的话,不会出现在此处) if(pbLocked) GlobalUnlock(hg); if(hg) GlobalFree(hg);
} catch(CString exMsg) { exMsg=L"CopyByteArrayToISream(BYTE*,DWORD,IStream **):"+ exMsg; CamException::WriteToFile(exMsg); } catch(CException* e) { TCHARszCause[255]; e->GetErrorMessage(szCause, 255); CString exMsg=CString(szCause); exMsg=L"CopyByteArrayToISream(BYTE*,DWORD,IStream **):"+ exMsg; CamException::WriteToFile(exMsg); }
}
BOOLGetImage::GetEnCodecCLSID( IImagingFactory * pImagingFactory, WCHAR* wszMimeType , CLSID * pclsid ) { UINTuiCount; ImageCodecInfo * codecs; HRESULThr; BOOLfRet = FALSE; //枚举系统已经安装的编码器 hr = pImagingFactory->GetInstalledEncoders(&uiCount, &codecs); //查找制定编码器的CLSID for(UINTi = 0; i < uiCount; i++) { if(wszMimeType && !wcscmp(wszMimeType, codecs[i].MimeType)) { *pclsid = codecs[i].Clsid; fRet = TRUE; break; } } //释放内存 CoTaskMemFree(codecs); // returnfRet; } |
截止上面已经完成了在内存当中对图片的转换了。
二、使用C#项目调用DLL
里面为了防止内存泄漏,专程让这个转换做了1000次,最后发现没有问题了。
?
usingSystem; usingSystem.Collections.Generic; usingSystem.Text; usingSystem.Runtime.InteropServices;//引入dll文件中的函数
// 添加新的命名空间。 usingSystem.IO; //using System.Drawing.Imaging; //using System.Drawing;
namespaceWinCeCsUseDll { classProgram {
[DllImport("WinCeCppCamdll.dll", CharSet = CharSet.Auto)]//WinCE平台下,居然没有ANSI这个编码选项。 privatestaticexternvoidGetCamShoot( intimgWidth,//图片宽度 intimgHeight,//图片高度 refIntPtr ppOutMallocJpegData,//传出的JPG图片数据实体 refintpdwOutJpegMemSize,//传出的JPG图片数据的大小 refintpState//状态码:记录在执行此函数的过程中可能出现的问题 );
[DllImport("WinCeCppCamdll.dll", CharSet = CharSet.Auto)]//WinCE平台下,居然没有ANSI这个编码选项。 privatestaticexternvoidFreeMemory(refIntPtr intPtr);
staticvoidMain(string[] args) { try { #region 用C#承接C++的DLL开辟的内存空间中的数据 intimageWidth = 640; intimageHeight = 480;
for(inti = 0; i < 10000; i++) { //下面再对内存区间进行传递 intmemSize = 0; intintState = 0; IntPtr intPtr =newIntPtr();
GetCamShoot(imageWidth, imageHeight,refintPtr,refmemSize,refintState);
////因为采用 致远公司提供的驱动有点奇怪,每次捕捉的好像都是一一次内存中的东西 ////如果是第一次启动程序,那么会出现没有数据的情况。所以需要进行一次容错--再读一次数据 //if (intPtr.Equals(IntPtr.Zero)) //{ // // GetCamShoot(ref intPtr, ref memSize, ref intState); //}
byte[] btTemp =newbyte[memSize]; Marshal.Copy(intPtr, btTemp, 0, memSize);
//将BYTE数组写成文件--测试代码 stringpath ="\\"; stringSendFileName ="recvBmpData.jpg"; FileStream MyFileStream =newFileStream(path + SendFileName, FileMode.Create, FileAccess.Write); MyFileStream.Write(btTemp, 0, btTemp.Length);//将接收到的数据包写入到文件流对象 MyFileStream.Close();//关闭文件流
////Marshal.FreeHGlobal(intPtr); FreeMemory(refintPtr); ////Marshal.FreeCoTaskMem(intPtr);//free tha memory---用FreeHGlobal释放会出现错误,不知道这个函数是不是真正实现了释放。 ////intPtr = IntPtr.Zero; if(i == 9999) break; } #endregion }catch(Exception e) { inta = 3; }
} } } |
虽然说今后可能再也不会碰这些东西了,但这毕竟是自己几个月的心血,所以还是贴下来吧,里面涉及的知识点太多了,今后自己有可能还有些参考价值的。