zoukankan      html  css  js  c++  java
  • WinCE平台下BMP转JPG代码备份

      这大概是一年前做的事情了,当时的项目要求在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;
                }
    
             
            }
        }
    }
    

      

      虽然说今后可能再也不会碰这些东西了,但这毕竟是自己几个月的心血,所以还是贴下来吧,里面涉及的知识点太多了,今后自己有可能还有些参考价值的。

  • 相关阅读:
    Tips_of_JS 之 利用JS实现水仙花数的寻找与实现斐波那契数列
    我的天!居然可以这么“弹”!—— 弹性盒布局属性详述
    震惊,正儿八经的网页居然在手机上这样显示!
    这是假的JS——利用CSS Animation实现banner图非交互循环播放
    小K的H5之旅-HTML5与CSS3部分新属性浅见
    CSS小技巧-煎蛋的画法~
    小K的H5之旅-实战篇(一)
    SSM+Redis简介
    Hadoop HA(高可用搭建)
    hadoop完全分布式搭建(非高可用)
  • 原文地址:https://www.cnblogs.com/beer/p/2163219.html
Copyright © 2011-2022 走看看