WinCE中解决“图片采集及压缩”问题的开发历程

来源:互联网 发布:网络流行文体 编辑:程序博客网 时间:2024/05/07 00:21

代码涉及知识点:

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的视频捕获,如果bIsRGBbIsYUVFALSE即为关闭视频捕获,

    **                          bIsRGBbIsYUV其中任一个为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、全屏模式下,2RGB通道图像设置值大于360*288个象素

    ** input parameters:        dwXSize:  预览图像的X坐标(以LCD的左上角为原点,可以为负值)

    **                          dwYSize:  预览图像的Y坐标(以LCD的左上角为原点,可以为负值)

    ** output parameters:       

    ** Returned value:          TRUE:成功;FALSE:失败

    *********************************************************************************************************/

     

 

 

 

    /*********************************************************************************************************

    ** Function name:           epcCamSetImage

    ** Descriptions:            本函数用于设置Camera输出图像的大小包含RGB通道和YUV通道的视频输出大小

    **                          打开该接口驱动后,RGBYUV图像大小默认为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的视频捕获,如果bIsRGBbIsYUVFALSE即为关闭视频捕获,

**                          bIsRGBbIsYUV其中任一个为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、全屏模式下,2RGB通道图像设置值大于360*288个象素

** input parameters:        dwXSize:  预览图像的X坐标(以LCD的左上角为原点,可以为负值)

**                          dwYSize:  预览图像的Y坐标(以LCD的左上角为原点,可以为负值)

** output parameters:       

** Returned value:          TRUE:成功;FALSE:失败

*********************************************************************************************************/

 

 

 

 

/*********************************************************************************************************

** Function name:           epcCamSetImage

** Descriptions:            本函数用于设置Camera输出图像的大小包含RGB通道和YUV通道的视频输出大小

**                          打开该接口驱动后,RGBYUV图像大小默认为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的图片数据全部COPYpcBmpData中了----这里可以通过读文件的形式将这些数据读上来。!!!!!!

    //只需要在此处将那个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的图片数据全部COPYpcBmpData中了----这里可以通过读文件的形式将这些数据读上来。!!!!!!

    //只需要在此处将那个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的图片数据全部COPYpcBmpData中了----这里可以通过读文件的形式将这些数据读上来。!!!!!!

    //只需要在此处将那个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接口作为一个槽或者管道来理解;

        //是用于负责pImageEncoderpImageDecoder之间的传输

        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;

            }

 

          

        }

    }

}

  

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