这大概是一年前做的事情了,当时的项目要求在WinCE平台下BMP转JPG,然后自己折腾了好几个月才终于搞定,现在时间过去了快一年了,估计自己今后再也不会碰WinCE相关的东西了吧,而且也准备把相关的学习笔记和代码项目全部删除掉。这些没有经过整理过的东西,放在电脑上也是垃圾,还不如整理一下,放到网上,让有需要的同学借鉴参考一下吧。
开发环境:VS2005
开发平台:EPC6960 WinCE开发板
主要目标:在WinCE平台下完成BMP图片转JPG
实现方法:使用C++编写转换的DLL文件,使用C#编写界面,然后调用DLL
代码涉及知识点:
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。这样方便读取每一帧数据
*/
typedef struct __PINGPONG_PR
{
unsigned int uiRGB_Addr;
unsigned char flag; /* 为1时候,视频数据有效 */
} PINGPONG_PR;
/*
* 对应CAM_IOCTL_SAMSUNG_CAM,打开YUV通道后,从uiY_Addr, uiCb_Addr, uiCr_Addr中获取视频图像数据,注意访
* 问三个地址时,必须采用内核模式(kernel mode),使用函数 SetKMode(TRUE),并在读取地址数据后设置flag = 0,
* 如果有下一帧数据来时,底层会将flag设为1,并设置YUV三个地址值。这样方便读取每一帧数据
*/
typedef struct PINGPONG
{
unsigned int uiY_Addr;
unsigned int uiCb_Addr;
unsigned int uiCr_Addr;
unsigned char flag;
} PINGPONG;
/*
* 此结构体用于设置视频输出图像的大小,视频输出包含两个通道:RGB通道和YUV通道,其中RGB通道为RGB565数据
* 格式,视频预览的时候使用RGB通道
*/
typedef struct __IMAGE_SIZE
{
DWORD dwRGB_Width; /* RGB 通道的输出图像的宽度 */
DWORD dwRGB_Height; /* RGB 通道的输出图像的高度 */
DWORD dwYUV_Width; /* YUV 通道的输出图像的宽度 */
DWORD dwYUV_Height; /* YUV 通道的输出图像的高度 */
DWORD dwHorOffset; /* 视频源的水平剪切偏移 */
DWORD dwVerOffset; /* 视频源的垂直剪切偏移 */
} IMAGE_SIZE;
typedef BOOL(*pEpcCamCapture)(BOOL bIsRGB, BOOL bIsYUV);
typedef BOOL(*pEpcCamPreviewOn)(DWORD dwXSize, DWORD dwYSize);
typedef BOOL(*pEpcCamSetImage)(IMAGE_SIZE* pImageSize);
typedef BOOL(*pEpcCamGetRgbFrame)(PINGPONG_PR *prAddInfo);
class EpcsCam
{
public:
EpcsCam(void);
public:
~EpcsCam(void);
public:
HINSTANCE hDLL;//载入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:失败
*********************************************************************************************************/
BOOL epcCamCapture (BOOL bIsRGB, BOOL bIsYUV);
BOOL epcCamPreviewOn (DWORD dwXSize, DWORD dwYSize);
BOOL epcCamSetImage (IMAGE_SIZE* pImageSize);
BOOL epcCamGetRgbFrame (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文件;
}
BOOL EpcsCam::epcCamCapture (BOOL bIsRGB, BOOL bIsYUV)
{
BOOL bCaptureSucced=FALSE;
pEpcCamCapture epcCamCapture =NULL;
epcCamCapture=(pEpcCamCapture)GetProcAddress(hDLL,CString("epcCamCapture"));
if (epcCamCapture)
{
bCaptureSucced=epcCamCapture(bIsRGB,bIsYUV);
}
return bCaptureSucced;
}
BOOL EpcsCam::epcCamPreviewOn (DWORD dwXSize, DWORD dwYSize)
{
BOOL bPreviewOnSucced=FALSE;
pEpcCamPreviewOn epcCamPreviewOn =NULL;
epcCamPreviewOn=(pEpcCamPreviewOn)GetProcAddress(hDLL,CString("epcCamPreviewOn"));
if (epcCamPreviewOn)
{
bPreviewOnSucced=epcCamPreviewOn(dwXSize,dwYSize);
}
return bPreviewOnSucced;
}
BOOL EpcsCam::epcCamSetImage (IMAGE_SIZE* pImageSize)
{
BOOL bSetImageSucced=FALSE;
pEpcCamSetImage epcCamSetImage =NULL;
epcCamSetImage=(pEpcCamSetImage)GetProcAddress(hDLL,CString("epcCamSetImage"));
if (epcCamSetImage)
{
bSetImageSucced=epcCamSetImage(pImageSize);
}
return bSetImageSucced;
}
BOOL EpcsCam::epcCamGetRgbFrame (PINGPONG_PR *prAddInfo)
{
BOOL betRgbFrameSucced=FALSE;
pEpcCamGetRgbFrame epcCamGetRgbFrame =NULL;
epcCamGetRgbFrame=(pEpcCamGetRgbFrame)GetProcAddress(hDLL,CString("epcCamGetRgbFrame"));
if (epcCamGetRgbFrame)
{
betRgbFrameSucced=epcCamGetRgbFrame(prAddInfo);
}
return betRgbFrameSucced;
}
1.2保存位图和保存异常日志等文件操作
FileOperate.h
#pragma once
class FileOperate
{
public:
FileOperate(void);
~FileOperate(void);
public:
static void WriteLogMsg(char chLogMsg[]);
static CString GetTimeTag();
#if 1
static void WriteBin(char chBin[]);
//根据数据保存图片
static BOOL bmpSaveImage (PTSTR pstrFileName, BITMAPFILEHEADER * pbmfh);
// 保存位图
static void SaveBitMap(void);
static CString SaveBmp(char *pcBmpData,char *bmpFileData);
static CString SaveBmp0(BYTE *pcBmpData);//C++调用的函数
#endif
public:
static void ImageConvertDemo(
BYTE *pInBmp565Data,//输入的RGB565位图的数据实体部分(不包括文件头等信息)
DWORD dwBitMapDataSize,//位图数据实体长度(不包括文件头等信息)
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)
{
}
void FileOperate::WriteLogMsg(char chLogMsg[])
{
char strFilePath[40] = "\\FlashDisk2\\Log\\";//如果是"\\Log\\"则到了当前盘符的根目录下了。
char strTimeFileName[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;
}
}
}
char strTimeTag[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);//换行
int i=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"
return strTimetag;
}
#if 1
void FileOperate::WriteBin(char chBin[])
{
char strFilePath[40] = "\\FlashDisk2\\Bins\\";//如果是"\\Log\\"则到了当前盘符的根目录下了。
char strTimeFileName[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);
}
}
}
char strTimeTag[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);
int i=fclose(fp);
if (i==0)
{
printf("succeed!\n");
}else
{
printf("fail!\n");
}
}
// 保存位图--最原来的模型
void FileOperate::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();//关闭文件
}
//带参数的保存位图函数
BOOL FileOperate::bmpSaveImage(PTSTR pstrFileName, BITMAPFILEHEADER *pbmfh)
{
BOOL bSuccess ;
DWORD dwBytesWritten ;
HANDLE hFile;
hFile = CreateFile ( pstrFileName, GENERIC_WRITE, 0, NULL,
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL) ;
if (hFile == INVALID_HANDLE_VALUE) {
return FALSE ;
}
bSuccess = WriteFile (hFile, pbmfh, pbmfh->bfSize, &dwBytesWritten, NULL);
CloseHandle (hFile) ;
if (!bSuccess || (dwBytesWritten != pbmfh->bfSize)) {
DeleteFile (pstrFileName) ;
return FALSE ;
}
return TRUE ;
}
//************************************
// 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);
return cstrPathname;
}
//************************************
// 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);
return cstrPathname;
}
#endif
//pcBmpDataTemp--从摄像头中得到的565数据区内容
void FileOperate::ImageConvertDemo(BYTE *pInBmp565Data,//输入的RGB565位图的数据实体部分--不包括位图文件等信息
DWORD dwBitMapDataSize,//位图数据实体长度(不包括文件头等信息)153600
BYTE **ppOutMallocData,//传出的JPG图片数据实体
DWORD * pdwOutJpegMemSize,//传出的JPG图片数据的大小
int * pState //状态码:记录在执行此函数的过程中可能出现的问题
)
{
BYTE * pOutRgb555BmpData=NULL;//输出的555格式的位图数据实体
DWORD dwRgb555BmpFileDataLength=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;
DWORD dwpJpegDataLength;//Jpeg数组的长度
imgDemo.ConvertRgb555BmpToJpgInMem(pOutRgb555BmpData,dwRgb555BmpFileDataLength,&pJpegData,&dwpJpegDataLength);//因为是在函数内部动态分配的内存,所以需要用指针的指针
//传出数据
*pdwOutJpegMemSize=dwpJpegDataLength;//传出长度---在最终代码中要简化
*ppOutMallocData=pJpegData;
}
1.3转换图片格式
GetImage.h
#pragma once
#include "initguid.h "//如果不引用此头文件,就会出现 无法解析外部符号的错误
#include "imaging.h"//图片转码测试
class GetImage
{
public:
GetImage(DWORD dwRGB_Width,DWORD dwRGB_Height);
GetImage(void);
~GetImage(void);
public:
DWORD dwRGB_Width; /* RGB 通道的输出图像的宽度 */
DWORD dwRGB_Height; /* RGB 通道的输出图像的高度 */
public:
//转换图片格式,并得到jpeg文件的数组
void GetJpegBytes(
BYTE *pInBmp565Data,//输入的RGB565位图的数据实体部分(不包括文件头等信息)
DWORD dwBitMapDataSize,//位图数据实体长度(不包括文件头等信息)
BYTE **ppOutMallocData,//传出的JPG图片数据实体的指针
DWORD * pdwOutJpegMemSize,//传出的JPG图片数据的大小
int * pState //状态码:记录在执行此函数的过程中可能出现的问题
);
private:
//将Rgb565编码格式的位图转成Rgb555的位图
void ConvertBmpRgb565To555(
BYTE * pInRgb565BmpData, //输入的565格式的位图数据实体
DWORD dwRgb555BmpFileDataLength,//位图文件大小
BYTE ** ppOutRgb555BmpData//输出的555格式的位图数据实体
);
//将数组转换到IStream中
void CopyByteArrayToISream(
BYTE *pInByteArray,//输入的字节数组
DWORD dwArrayLength,//字节数组的长度
IStream **ppOutIStream//传出的由字节转换的流
);
/*
*函数介绍:根据编码器类型名称,得到指定的编码器CLSID
*入口参数:pImagingFactory: Image工厂接口对象
wszMimeType : Image编码格式名称
*出口参数:pclsid :编码器的CLSID
*返回值:TRUE : 成功; FALSE: 失败
*/
BOOL GetEnCodecCLSID(IImagingFactory * pImagingFactory, WCHAR * wszMimeType , CLSID * pclsid);
//Rgb555编码的BMP位图转JPG--在内存中进行
void ConvertRgb555BmpToJpgInMem(
BYTE * pInRgb555BmpFileData, //输入的RGB555位图文件流--包括位图数据实体及文件和位图信息
DWORD dwRgb555BmpFileDataLength,//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(DWORD dwWidth,DWORD dwHeight)
{
dwRGB_Height=dwHeight;
dwRGB_Width=dwWidth;
}
GetImage::~GetImage(void)
{
}
void GetImage::GetJpegBytes(
BYTE *pInBmp565Data,//输入的RGB565位图的数据实体部分--不包括位图文件等信息
DWORD dwBitMapDataSize,//位图数据实体长度(不包括文件头等信息)153600
BYTE **ppOutMallocData,//传出的JPG图片数据实体
DWORD * pdwOutJpegMemSize,//传出的JPG图片数据的大小
int * pState //状态码:记录在执行此函数的过程中可能出现的问题
)
{
try
{
BYTE * pOutRgb555BmpData=NULL;//输出的555格式的位图数据实体
DWORD dwRgb555BmpFileDataLength=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)
{
throw CString("ConvertBmpRgb565To555位图图片格式转码失败");
}
BYTE * pJpegData=NULL;
DWORD dwpJpegDataLength;//Jpeg数组的长度
ConvertRgb555BmpToJpgInMem(pOutRgb555BmpData,dwRgb555BmpFileDataLength,&pJpegData,&dwpJpegDataLength);
//因为是在函数内部动态分配的内存,所以需要用指针的指针
if (pOutRgb555BmpData!=NULL)
{
free(pOutRgb555BmpData);//555位图数据使用完毕后,就释放
pOutRgb555BmpData=NULL;
}
if (pJpegData==NULL)
{
throw CString("ConvertRgb555BmpToJpgInMem位图压缩失败");
}
//传出数据
*pdwOutJpegMemSize=dwpJpegDataLength;//传出长度---在最终代码中要简化
*ppOutMallocData=pJpegData;
}
catch(CString exMsg)
{
exMsg=L"GetJpegBytes(BYTE*,DWORD,BYTE**,DWORD*,int*):" + exMsg;
CamException::WriteToFile(exMsg);
}
catch (CException* e)
{
TCHAR szCause[255];
e->GetErrorMessage(szCause, 255);
CString exMsg=CString(szCause);
exMsg=L"GetJpegBytes(BYTE*,DWORD,BYTE**,DWORD*,int*):" + exMsg;
CamException::WriteToFile(exMsg);
}
}
//将Rgb565编码格式的位图转成Rgb555的位图---位图的大小不会变化,只是数据的编码方式发生变化
void GetImage::ConvertBmpRgb565To555(
BYTE * pInRgb565BmpData,//输入的565格式的位图数据实体----不包括位图文件信息
DWORD dwRgb555BmpFileDataLength,//位图文件大小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)
{
throw CString("pFileHead位图信息头内存分配失败");
}
pBmpInfo = (BITMAPINFO *)malloc(dwInfoSize);
if (pBmpInfo==NULL)
{
free(pFileHead);
pFileHead==NULL;//释放已经申请到的内存
throw CString("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;
throw CString("p555Data内存分配失败");
}
DWORD width=dwRGB_Width;//320
DWORD height=dwRGB_Height;//240
int pitch=width+width%2;//偏移量
for (int i=0;i<height;i++)//图片的高度是240
{
for (int j=0;j<width;j++)
{
//分解出RGB三分量---RGB565的
UCHAR b=pcBmpData[(i*pitch+j)*2]&0x1F;
UCHAR g=((((pcBmpData[(i*pitch+j)*2+1]<<5)&0xFF)>>2) & 0x38) +((pcBmpData[(i*pitch+j)*2]>>5)&0x07);
UCHAR r=(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;
throw CString("*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)
{
TCHAR szCause[255];
e->GetErrorMessage(szCause, 255);
CString exMsg=CString(szCause);
exMsg=L"ConvertBmpRgb565To555(BYTE*,DWORD,BYTE**):" + exMsg;
CamException::WriteToFile(exMsg);
}
}
// //Rgb555编码的BMP位图转JPG--在内存中进行
void GetImage::ConvertRgb555BmpToJpgInMem(
BYTE * pInRgb555BmpFileData, //输入的RGB555位图文件流--包括位图数据实体及文件和位图信息
DWORD dwRgb555BmpFileDataLength,//RGB555位图文件流的长度
BYTE ** ppOutJpegData,//传出的JPG文件数据流
DWORD * dwpOutJpegDataLegth//JPG文件流大小
)
{
try
{
#pragma region
HRESULT hr;//保存每个步骤的中间结果,判断过程运行是否正确----到时候有必要写个异常日志记录
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");
goto finish;
}
//创建解码器接口
if (FAILED(hr = pImagingFactory->CreateImageDecoder(pRgb555BmpStream, DecoderInitFlagBuiltIn1st, &pImageDecoder)))
{
goto finish;
}
//根据编码器类型名称得到编码器CLSID
if (!GetEnCodecCLSID(pImagingFactory,tszMime, &clsidEncoder ))//tszMime = L"image/jpeg"; //指定转换后,图象文件的格式
{
goto finish;
}
if (FAILED(hr = CreateStreamOnHGlobal(NULL,TRUE,&pJpegStream)))//必需要和某个内存区域关联,或者进行一次实例化,比如用COleStreamFile
{
goto finish;
}
if (FAILED(hr = pImagingFactory->CreateImageEncoderToStream(&clsidEncoder, pJpegStream, &pImageEncoder)))
{
goto finish;
}
//得到编码器接口的sink对象。此ImageSink接口作为一个槽或者管道来理解;
//是用于负责pImageEncoder和pImageDecoder之间的传输
if (FAILED(hr = pImageEncoder->GetEncodeSink(&pImageSink)))
{
goto finish;
}
//开始解码
if (FAILED(hr = pImageDecoder->BeginDecode(pImageSink, NULL)))
{
goto finish;
}
//循环解码,直到结束
for(;;)//for循环其实只运行了一个周期
{
//解码
hr = pImageDecoder->Decode();//解码后,生成一个8K的文件
//继续解码后面的部分
if (E_PENDING == hr)
{
Sleep(500);
} //失败
else if (FAILED(hr))
{
//终止解码
pImageDecoder->EndDecode(hr);
goto finish;
}
else
{
//解码成功
break;
}
}
pImageDecoder->EndDecode(hr);//结束解码
pImageSink->Release();//释放pImageSink对象
pImageSink = NULL;
pImageEncoder->TerminateEncoder();//结束编码,此时就已经完成了文件格式的转换
#pragma region //从流中提取数据到BYTE数组中
DWORD dwStreamLengthLowPart;//状态中的长度分量--低位(因为实际图片数据不需要高位那么长)
//得到pJpegStream的长度--然后提取出数据,保存到BYTE数组中
pIStreamState=(STATSTG *)malloc(sizeof(STATSTG));//如果不动态开辟空间,将无法传值进来。
if (NULL == pIStreamState)//如果申请内存没有成功
{
CamException::WriteToFile(L"pIStreamState申请内存失败");
goto finish;
}
if (FAILED(hr=pJpegStream->Stat(pIStreamState,STATFLAG_NONAME)))
{
CamException::WriteToFile(L"pJpegStream获取状态失败");
goto finish;
}
dwStreamLengthLowPart = pIStreamState->cbSize.LowPart;//取出流状态中的长度分量
free(pIStreamState);
pIStreamState=NULL;//指针置空,防止野指针出现
pJpegData = (BYTE *)malloc(dwStreamLengthLowPart);//用来存储从文件流中剥出来的数据。
if (NULL == pJpegData)//如果申请内存没有成功
{
goto finish;
}
//将流指针移到流起点。
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))
{
goto finish;
}
#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)
{
TCHAR szCause[255];
e->GetErrorMessage(szCause, 255);
CString exMsg=CString(szCause);
exMsg=L"ConvertBmpRgb565To555(BYTE*,DWORD,BYTE**):" + exMsg;
CamException::WriteToFile(exMsg);
}
}
void GetImage::CopyByteArrayToISream(
BYTE *pInByteArray,//输入的字节数组
DWORD dwArrayLength,//字节数组的长度
IStream **ppOutIStream//传出的由字节转换的流
)
{
try
{
HRESULT hrRet = S_FALSE;
HGLOBAL hg = NULL;
BYTE* pbLocked = NULL;
//分配内存--此方法已经过时,现在一般都用malloc或者new了
hg = GlobalAlloc(GMEM_MOVEABLE, dwArrayLength);
if (NULL == hg)
{
CamException::WriteToFile(L"hg分配内存失败");
goto error;
}
//得到已经分配的内存指针
pbLocked = (BYTE*) GlobalLock(hg);
if (NULL == pbLocked)
{
CamException::WriteToFile(L"pbLocked获取指针失败");
goto error;
}
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)
{
TCHAR szCause[255];
e->GetErrorMessage(szCause, 255);
CString exMsg=CString(szCause);
exMsg=L"CopyByteArrayToISream(BYTE*,DWORD,IStream **):" + exMsg;
CamException::WriteToFile(exMsg);
}
}
BOOL GetImage::GetEnCodecCLSID(
IImagingFactory * pImagingFactory,
WCHAR * wszMimeType ,
CLSID * pclsid
)
{
UINT uiCount;
ImageCodecInfo * codecs;
HRESULT hr;
BOOL fRet = FALSE;
//枚举系统已经安装的编码器
hr = pImagingFactory->GetInstalledEncoders(&uiCount, &codecs);
//查找制定编码器的CLSID
for (UINT i = 0; i < uiCount; i++)
{
if (wszMimeType && !wcscmp(wszMimeType, codecs[i].MimeType))
{
*pclsid = codecs[i].Clsid;
fRet = TRUE;
break;
}
}
//释放内存
CoTaskMemFree(codecs);
//
return fRet;
}
截止上面已经完成了在内存当中对图片的转换了。
二、使用C#项目调用DLL
里面为了防止内存泄漏,专程让这个转换做了1000次,最后发现没有问题了。
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;//引入dll文件中的函数
// 添加新的命名空间。
using System.IO;
//using System.Drawing.Imaging;
//using System.Drawing;
namespace WinCeCsUseDll
{
class Program
{
[DllImport("WinCeCppCamdll.dll", CharSet = CharSet.Auto)]//WinCE平台下,居然没有ANSI这个编码选项。
private static extern void GetCamShoot(
int imgWidth,//图片宽度
int imgHeight,//图片高度
ref IntPtr ppOutMallocJpegData,//传出的JPG图片数据实体
ref int pdwOutJpegMemSize,//传出的JPG图片数据的大小
ref int pState //状态码:记录在执行此函数的过程中可能出现的问题
);
[DllImport("WinCeCppCamdll.dll", CharSet = CharSet.Auto)]//WinCE平台下,居然没有ANSI这个编码选项。
private static extern void FreeMemory(ref IntPtr intPtr);
static void Main(string[] args)
{
try
{
#region 用C#承接C++的DLL开辟的内存空间中的数据
int imageWidth = 640;
int imageHeight = 480;
for (int i = 0; i < 10000; i++)
{
//下面再对内存区间进行传递
int memSize = 0;
int intState = 0;
IntPtr intPtr = new IntPtr();
GetCamShoot(imageWidth, imageHeight, ref intPtr, ref memSize, ref intState);
////因为采用 致远公司提供的驱动有点奇怪,每次捕捉的好像都是一一次内存中的东西
////如果是第一次启动程序,那么会出现没有数据的情况。所以需要进行一次容错--再读一次数据
//if (intPtr.Equals(IntPtr.Zero))
//{
// // GetCamShoot(ref intPtr, ref memSize, ref intState);
//}
byte[] btTemp = new byte[memSize];
Marshal.Copy(intPtr, btTemp, 0, memSize);
//将BYTE数组写成文件--测试代码
string path = "\\";
string SendFileName = "recvBmpData.jpg";
FileStream MyFileStream = new FileStream(path + SendFileName, FileMode.Create, FileAccess.Write);
MyFileStream.Write(btTemp, 0, btTemp.Length); //将接收到的数据包写入到文件流对象
MyFileStream.Close();//关闭文件流
////Marshal.FreeHGlobal(intPtr);
FreeMemory(ref intPtr);
////Marshal.FreeCoTaskMem(intPtr);//free tha memory---用FreeHGlobal释放会出现错误,不知道这个函数是不是真正实现了释放。
////intPtr = IntPtr.Zero;
if (i == 9999)
break;
}
#endregion
}catch(Exception e)
{
int a = 3;
}
}
}
}
虽然说今后可能再也不会碰这些东西了,但这毕竟是自己几个月的心血,所以还是贴下来吧,里面涉及的知识点太多了,今后自己有可能还有些参考价值的。
扫码关注腾讯云开发者
领取腾讯云代金券
Copyright © 2013 - 2025 Tencent Cloud. All Rights Reserved. 腾讯云 版权所有
深圳市腾讯计算机系统有限公司 ICP备案/许可证号:粤B2-20090059 深公网安备号 44030502008569
腾讯云计算(北京)有限责任公司 京ICP证150476号 | 京ICP备11018762号 | 京公网安备号11010802020287
Copyright © 2013 - 2025 Tencent Cloud.
All Rights Reserved. 腾讯云 版权所有