1. 程式人生 > >BMP與JPG圖片格式的互相轉換

BMP與JPG圖片格式的互相轉換

近天要用到bmp與jpg之間互想轉換,在網上查看了許多資料,如jpeglib,cximage,zlib,最後找到了GDI+利用流來轉換,此方法最簡單,可以實現在檔案->檔案,檔案->記憶體,記憶體->記憶體,記憶體->檔案儲存,對於網路傳送圖片非常實用,通常320*240*24b的225k的BMP轉成JPG後大約15.6K,壓縮比15:1.

轉換邏輯如下:

1.載入bmp或jpg檔案,取得檔案資料大小通過GlobalAlloc分配堆記憶體空間返回的記憶體控制代碼作為建立流介面指標的記憶體控制代碼,建立流介面.

2.鎖定此記憶體空間,將圖片資料memcpy到此空間中

3.通過流建立GDI+中的圖片

Image *imImage = NULL;
 imImage = Image::FromStream(pStmBmp, FALSE);

4.取得要編碼的GUID詳見後代碼

5.儲存此圖到檔案或流中

如果只是BMP點陣圖資料則需自已構建點陣圖檔案頭和點陣圖資訊頭

程式碼:

int GetImageCLSID(const  WCHAR*format,  CLSID* pCLSID)  
{//得到格式為format的影象檔案的編碼值,訪問該格式影象的COM元件的GUID值儲存在pCLSID中  
 UINT  num = 0;  
 UINT  size = 0;  
 ImageCodecInfo *pImageCodecInfo = NULL;  
 GetImageEncodersSize(&num, &size);  
 if(size == 0)  
  return FALSE;   //編碼資訊不可用  
 //分配記憶體  
 pImageCodecInfo = (ImageCodecInfo*)(malloc(size));  
 if(pImageCodecInfo == NULL)  
  return FALSE;   //   分配失敗  
 //獲得系統中可用的編碼方式的所有資訊  
 GetImageEncoders(num, size, pImageCodecInfo);  
 //在可用編碼資訊中查詢format格式是否被支援  
 for(UINT i=0; i<num; ++i)  
 {   //MimeType:編碼方式的具體描述  
  if(wcscmp(pImageCodecInfo[i].MimeType, format) == 0)  
  {  
   *pCLSID = pImageCodecInfo[i].Clsid;  
   free(pImageCodecInfo);  
   return TRUE;
  }  
 }  
 free(pImageCodecInfo);  
 return   FALSE;  
}

void CTest_GDI2Dlg::BMP2JPG()
{
 CFile file(“test.bmp”, CFile::modeRead);
 int fileLen = file.GetLength();
 HGLOBAL hMemBmp = GlobalAlloc(GPTR, fileLen); 

 BYTE *pbyBmp = (BYTE *)GlobalLock(hMemBmp);
 file.ReadHuge(pbyBmp, fileLen);
 file.Close();

GlobalUnlock(hMemBmp);

//如果只有圖位資料資訊則要自已構建資訊頭,下面註釋部分

測試構建320*240*24b點陣圖檔案

/*BITMAPFILEHEADER fileheader;
 BITMAPINFOHEADER infoH;

 memset(&fileheader, 0, sizeof(BITMAPFILEHEADER));
 fileheader.bfType = 19778;//固定為’BM’
 fileheader.bfSize = 320*240*3+54;//構造時注意+54位元組頭
 fileheader.bfOffBits = 54;
 
 infoH.biSize = sizeof(BITMAPINFOHEADER);
 infoH.biWidth = 320;
 infoH.biHeight = 240;
 infoH.biPlanes = 1;
 infoH.biBitCount = 24;
 infoH.biCompression = BI_RGB;
 infoH.biSizeImage = 320*240*3;
 infoH.biXPelsPerMeter = 0;
 infoH.biYPelsPerMeter = 0;
 infoH.biClrUsed = 0;
 infoH.biClrImportant = 0;

 memcpy(pbyBmp, &fileheader, 14);
 memcpy(pbyBmp+14, &infoH, 40);*/

  //構建指向BMP的流
 IStream *pStmBmp = NULL;
 CreateStreamOnHGlobal(hMemBmp, FALSE, &pStmBmp);

 Image *imImage = NULL;
 imImage = Image::FromStream(pStmBmp, FALSE);

 USES_CONVERSION;
 CLSID clImageClsid;//這裡是要轉為jpeg格式
 GetImageCLSID(A2W(“image/jpeg”),  &clImageClsid);
 int ret = imImage->Save(A2W(“1.jpg”), &clImageClsid);//直接儲存為檔案

//下面可直接儲存在流中

 /*HGLOBAL hMemJpg = GlobalAlloc(GMEM_MOVEABLE, 0);

 IStream *pStmImage = NULL;
 CreateStreamOnHGlobal(hMemJpg, FALSE, &pStmImage);
 imImage->Save(pStmImage, &clImageClsid);

 LARGE_INTEGER liBegin = {0};
 pStmImage->Seek(liBegin, STREAM_SEEK_SET, NULL);
 BYTE *pbyjpg = (BYTE *)GlobalLock(hMemJpg);//這裡的pbyjpg就是轉換後的JPG資料可直接通過網路傳送
 
 int Len = GlobalSize(hMemJpg);//這就是轉為JPG後文件的大小了
  CFile filejpg(“2.jpg”, CFile::modeCreate | CFile::modeWrite);
 filejpg.Write(pbyjpg, Len);//這裡寫成檔案和前面直接儲存為檔案效果一樣
 filejpg.Close();

m_pBuf = new char[Len];
 memcpy(m_pBuf, pbyjpg, Len);//可以儲存此資料,任你操作哦
 GlobalUnlock(hMemJpg);

GlobalFree(hMemJpg);

 pStmImage->Release();*/
 pStmBmp->Release();
  GlobalFree(hMemBmp);
}

反之JPG轉BMP是1個道理,只是中間取得的編碼型別不同應該是GetImageCLSID(A2W(“image/bmp”),  &clImageClsid);

下面演示接收到網路上的JPG資料轉為BMP:m_pBuf假設儲存了接收到的JPG資料m_len是此JPG資料大小

void CTest_GDI2Dlg::JPG2BMP()
{
 // TODO: Add your control notification handler code here
 HGLOBAL hMemJpg = GlobalAlloc(GPTR, m_len);
 BYTE *pbyjpg = (BYTE *)GlobalLock(hMemJpg);
 memcpy(pbyjpg, m_pBuf, m_len);
 GlobalUnlock(hMemJpg);

 IStream *pStmJpg = NULL;
 CreateStreamOnHGlobal(hMemJpg, FALSE, &pStmJpg);

 Image *imImage = NULL; //從流中還原圖片
 imImage = Image::FromStream(pStmJpg, FALSE);

 USES_CONVERSION;
 CLSID clImageClsid;
 GetImageCLSID(A2W(“image/bmp”),  &clImageClsid);//取得BMP編碼
 int ret = imImage->Save(A2W(“3.bmp”), &clImageClsid);

//可直接儲存在流中,任你操作了哦

 /*HGLOBAL hMemBmp = GlobalAlloc(GMEM_MOVEABLE, 0);
 IStream *pStmBmp = NULL;
 CreateStreamOnHGlobal(hMemBmp, FALSE, &pStmBmp);
 imImage->Save(pStmBmp, &clImageClsid);

 int Len = GlobalSize(hMemBmp);//轉換後BMP檔案大小
 BYTE *pbyBmp = (BYTE *)GlobalLock(hMemBmp);//此資料就可直接呼叫API畫出來了
 CFile filejpg(“4.bmp”, CFile::modeCreate | CFile::modeWrite);
 filejpg.Write(pbyBmp, Len);
 filejpg.Close();
 GlobalUnlock(hMemBmp);

 pStmBmp->Release();

GlobalFree(hMemBmp);*/
 pStmJpg->Release();
 GlobalFree(hMemJpg);
}