2017-02-16 92 views
0

我有一個使用位圖的VC++ 6項目。我想以編程方式提取幾個位圖並保存爲.bmp文件。從.exe文件中提取.bmp

請給我一些建議,這樣做。

這些是我想要做的幾個步驟。

  1. 我在VC++ 6中有一個項目,它有一些由我在VC++位圖編輯器中創建的位圖。
  2. 我將點擊.exe中的一個菜單。
  3. 程序會從自身提取所有.bmp文件(它已經有了),將它們放在硬盤上保存爲.BMP

預先感謝 問候

ULKA

+1

是否要從外部可執行文件資源部分提取圖像?或者從運行程序中的自己的資源? –

+0

有像LoadResource,二進制FindResource的方法。見https://www.codeproject.com/Articles/4221/Adding-and-extracting-binary-resources – sameerkn

+0

請[編輯]你的問題,以顯示[你到目前爲止已經嘗試](http://whathaveyoutried.com) 。您應該包含您遇到問題的代碼[mcve],然後我們可以嘗試幫助解決特定問題。你還應該閱讀[問]。 –

回答

4

位圖資源在可執行文件中只是BITMAPFILEHEADER被剝離的位圖文件。 另請參閱:https://blogs.msdn.microsoft.com/oldnewthing/20091211-00/?p=15693

所以你需要做的是自己創建這個頭,並首先將它寫入文件。對於最常見的24位bpp位圖而言,這是相對容易的,但如果您還想支持其他位深度,則會涉及更多一點。

接下來寫入通過FindResource()/ LoadResource()/ LockResource()調用獲得的數據。

int main() 
{ 
    // Obtain a handle to the current executable 
    HMODULE hInst = ::GetModuleHandle(nullptr); 

    // Locate and load a bitmap resource of the executable 
    if(HRSRC hr = ::FindResource(hInst, MAKEINTRESOURCE(IDB_BITMAP1), RT_BITMAP)) 
     if(HGLOBAL hg = ::LoadResource(hInst, hr)) 
      if(auto pData = reinterpret_cast<const char*>(::LockResource(hg))) 
      { 
       DWORD resourceSize = ::SizeofResource(hInst, hr); 

       // Check if we safely read the complete BITMAPINFOHEADER 
       // (to prevent a GPF in case the resource data is corrupt). 
       if(resourceSize >= sizeof(BITMAPINFOHEADER)) 
       { 
        auto& bmih = reinterpret_cast<const BITMAPINFOHEADER&>(*pData); 

        // For simplicitly we can only save uncompressed bitmaps. 
        if(bmih.biCompression == BI_RGB) 
        { 
         // Calculate the size of the bitmap pixels in bytes. 
         // We use this to calculate BITMAPFILEHEADER::bfOffBits correctly. 
         // This is much easier than calculating the size of the color table. 
         DWORD widthBytes = (bmih.biBitCount * bmih.biWidth + 31)/32 * 4; 
         DWORD heightAbs = abs(bmih.biHeight); // height can be negative for a top-down bitmap! 
         DWORD pixelSizeBytes = widthBytes * heightAbs; 

         // Create the bitmap file header. 
         BITMAPFILEHEADER bfh = { 0 }; 
         bfh.bfType = 0x4D42;       // magic bytes: "BM" 
         bfh.bfSize = sizeof(bfh) + resourceSize; // total file size 
         bfh.bfOffBits = bfh.bfSize - pixelSizeBytes; // offset to bitmap pixels 

         // Write file header and bitmap resource data to file. 
         std::ofstream of("mybitmap1.bmp", std::ios::binary); 
         of.write(reinterpret_cast<const char*>(&bfh), sizeof(bfh)); 
         of.write(pData, resourceSize); 
        } 
       } 
      } 

    return 0; 
} 

編輯::

我原先的答案錯過一個決定性位(字面),即

代碼示例(1個BPP,4 BPP,8 BPP和24個BPP位圖測試)是ofstream構造函數的標記ios::binary。這就是爲什麼代碼不適用於亞瑟G.

那麼爲什麼它實際上爲我工作,即使沒有國旗?有趣的是,它只工作,因爲我的測試位圖沒有任何字節值爲10(不要相信程序員測試自己的代碼)!

默認情況下可能發生的一件事是行結尾將根據平臺默認值進行轉換。也就是說,'\ n'(ASCII碼= 10)將在Windows平臺上轉換爲「\ r \ n」。當然,這將完全搞亂位圖數據,因爲任何真實的位圖都可能在某處包含這個值。

所以我們必須明確告訴ofstream我們的數據不應該混淆,這正是ios :: binary標誌所做的。

編輯2:

只是爲了好玩我伸出我的例子爲1位正常工作,4位和每像素8位位圖了。 這有點多,因爲對於這些位深度,像素數組在BITMAPINFOHEADER之後不會立即開始。在像素數組來到顏色表之前,其大小必須添加到BITMAPFILEHEADER::bfOffBits

根據MSDN的說法,問題更加複雜,因爲即使位深度爲16或更大,也可以有一個可選的顏色表(「以優化系統調色板的性能」 - 無論這意味着什麼)! 通過從總減去像素陣列的尺寸見https://msdn.microsoft.com/en-us/library/windows/desktop/dd183376(v=vs.85).aspx(在「biClrUsed」)

因此,而不是包裹我的身邊何時以及如何使用色表,我只是計算BITMAPFILEHEADER::bfOffBits所有的骯髒細節頭部資源大小(已知)。

計算像素數組的大小相當簡單,但您必須注意以字節爲單位的寬度四捨五入爲4的下一個倍數(一個DWORD)。否則,保存位圖時,其以字節寬度不是4

獎金的倍數,你會得到錯誤讀取

維基百科擁有的一個漂亮的圖中的位圖文件格式相當的深入描述結構: https://en.wikipedia.org/wiki/BMP_file_format