国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開APP
userphoto
未登錄

開通VIP,暢享免費電子書等14項超值服

開通VIP
詳解用VC實現(xiàn)bmp位圖的打開 - fengqing888的日志 - 網(wǎng)易博客

詳解用VC實現(xiàn)bmp位圖的打開

技術(shù)_圖片編程 2009-12-18 13:59:17 閱讀262 評論0 字號:

我最近在學(xué)VC++數(shù)字圖像處理,作為一個初學(xué)者,萬里長征的第一步當然是打開一幅圖像,這幾天一直在看怎么實現(xiàn)這一功能,雖說簡單,但是如果這一步不能做到,那么下面也就無法進行了,所以我總結(jié)了一下這個過程,寫出來供大家參考。也希望大家多多批評啊。

這里我就不想介紹關(guān)于位圖的理論內(nèi)容了,只是寫一下實現(xiàn)的部分。

0.準備工作

創(chuàng)建一個SDI,工程名Test,“隱藏工具欄”和“打印和打印預(yù)覽”取消了,不用那么復(fù)雜,簡單點就行

1.創(chuàng)建菜單

創(chuàng)建兩個菜單:

Caption: 打開       ID: ID_FILE_OPEN

Caption: 顯示原圖   ID: IDM_YUANTU

2.對打開菜單進行響應(yīng)

右鍵打開菜單,建立類向?qū)?,在CTestDoc類中,進行COMMAND響應(yīng),生成OnFileOpen函數(shù),代碼如下:

void CTestDoc::OnFileOpen()

{

    //TODO: Add your command handler code here

    CFileDialogfileDlg(TRUE);//創(chuàng)建一個CfileDialog類對象fileDlg,第一個參數(shù)TRUE為打開對話框,若為FALSE,則為另存為

   fileDlg.m_ofn.lpstrTitle="圖片打開對話框";//設(shè)置打開對話框的標題

    fileDlg.m_ofn.lpstrFilter="BMPFiles(*.bmp)\0*.bmp\0\0";//設(shè)置打開的文件類型

   if(IDOK==fileDlg.DoModal())//這個語句有兩層意義,第一是dlg.DoModal()作用是彈出CPortDlg對話框,第二層是dlg.DoModal()==IDOK是你點擊了對話框上的OK按鈕就是說你同時做了上述兩件事時就執(zhí)行if語句后面的程序。

    filename.Format("%s",fileDlg.GetPathName());//將完整路徑通過Format函數(shù)以字符串類型存入filename中

★CDib.LoadFile(filename);//注意這里CDib不是類,而是CDib類的對象,對象名稱也為CDib,千萬不要弄混,類不能直接調(diào)用成員函數(shù),而類的對象則可以調(diào)用

}

其中,注意在CTestDoc類中,添加一個變量filename,Cstring類型,該變量作用是保存所指定的文件的文件完整路徑。

注意最后一行★。這一句代碼用來實現(xiàn)文件的讀?。ú缓@示)。這里用到了CDib類的對象CDib,因此需要在CTestDoc.h中添加CDib類的頭文件#include“Dib.h”,并且在CTestDoc類中添加這個對象,類型CDib,變量名稱CDib。然后執(zhí)行CDib類的成員函數(shù)LoadFile來讀取文件。

3.CDib類的操作

這是一個處理DIB位圖的專用類,封裝了一些相關(guān)的函數(shù)與變量,基類選為CObject類。

在Dib.h中做如下聲明:

class CDib : publicCObject

{

public:

    RGBQUAD* m_pRGB;

    BYTE* m_pData;

    UINT m_numberOfColors;

BOOLm_valid;

    BITMAPFILEHEADERbitmapFileHeader;//定義了一個文件頭結(jié)構(gòu)體的對象

   BITMAPINFOHEADER* m_pBitmapInfoHeader;//定義了一個指向信息頭的結(jié)構(gòu)體指針

    BITMAPINFO*m_pBitmapInfo;//定義了一個結(jié)構(gòu)體指針,BITMAPINFO是一個包含有信息頭,和調(diào)色板的結(jié)構(gòu)體。

    BYTE* pDib;

DWORD size;

charm_fileName[256];//定義字符數(shù)組用來存放文件路徑

public:

UINT GetNumberOfColors();

UINT GetHeight();

UINT GetWidth();

DWORD GetSize();

void LoadFile(const char* dibFileName);

CDib();

virtual~CDib();

};

CDib.cpp代碼如下:

CDib::CDib()

{

   size=0;//構(gòu)造函數(shù)初始化size

}

CDib::~CDib()

{

GlobalFreePtr(m_pBitmapInfo); //詳見說明(1)

}

voidCDib::LoadFile(const char* dibFileName)

{

   strcpy(m_fileName,dibFileName);//將路徑名稱拷貝到m_fileName之中

    CFile dibFile(m_fileName,CFile::modeRead);//創(chuàng)建CFile類對象,只讀方式

   dibFile.Read((void*)&bitmapFileHeader,sizeof(BITMAPFILEHEADER));//讀取文件頭的內(nèi)容

    if (bitmapFileHeader.bfType==0x4d42)//判斷是否為bmp格式,單步調(diào)試你會發(fā)現(xiàn),此時的bfType值并非0x4d42,而是19778.注意,這是十進制,只要轉(zhuǎn)換成十六進制即為0x4d42

    {

        DWORD fileLength =dibFile.GetLength();//讀取文件的大小,你可以試試跟蹤此值來看看它是否和你要打開的圖片大小一致

         size = fileLength-sizeof(BITMAPFILEHEADER);//文件大小-文件頭結(jié)構(gòu)體的大小,此時你會發(fā)現(xiàn),文件頭的大小的確是14字節(jié)

         pDib=(BYTE*)GlobalAllocPtr(GMEM_MOVEABLE, size);//詳見說明(2)

        dibFile.Read((void*)pDib,size);//通過讀取,把讀出的數(shù)據(jù)存入剛才分配的內(nèi)存之中

       dibFile.Close();//文件操作完成之后關(guān)閉文件

       m_pBitmapInfo = (BITMAPINFO*) pDib;//BITMAPINFO結(jié)構(gòu)體指針指向該內(nèi)存

        m_pBitmapInfoHeader =(BITMAPINFOHEADER*) pDib;//信息頭指向該內(nèi)存

       m_pRGB = (RGBQUAD*)(pDib +

   m_pBitmapInfoHeader->biSize);//調(diào)色板指針指向該內(nèi)存的調(diào)色板部分。因為pDib原本指向信息頭,偏移40字節(jié)(信息頭結(jié)構(gòu)體的大?。┲蟊愕搅苏{(diào)色板部分,因此用加法來實現(xiàn)指針的偏移

       int m_numberOfColors =GetNumberOfColors();//調(diào)用GetNumberOfColors函數(shù)來得到顏色數(shù)

        if (m_pBitmapInfoHeader->biClrUsed== 0)

           m_pBitmapInfoHeader->biClrUsed =

      m_numberOfColors;//把顏色數(shù)賦予biClrUsed之中

       DWORD colorTableSize = m_numberOfColors *

            sizeof(RGBQUAD);//用每個調(diào)色板結(jié)構(gòu)體大小乘以顏色數(shù)量,得到調(diào)色板的大小

        m_pData = pDib +m_pBitmapInfoHeader->biSize

           + colorTableSize;//這時候代表把m_pData指針指向?qū)嶋H圖像數(shù)據(jù)了

   if (m_pRGB == (RGBQUAD*)m_pData) //如果調(diào)色板指針位置和實際圖像位置指針指向位置相同,那就代表沒有調(diào)色板

   m_pRGB = NULL;//指針賦予空

       m_pBitmapInfoHeader->biSizeImage = GetSize();//賦予實際位圖的大小

   m_valid = TRUE;

    }   

    else//如果不是bmp位圖則失敗

    {

       m_valid = FALSE;

       AfxMessageBox("This isn't a bitmap file!");

    }

}

DWORD CDib::GetSize()

{

    if(m_pBitmapInfoHeader->biSizeImage != 0)

        return m_pBitmapInfoHeader->biSizeImage;

else

    {

        DWORD height = (DWORD)GetHeight();

        DWORD width =(DWORD) GetWidth();

        returnheight * width;

    }

}

UINTCDib::GetWidth()

{

    return (UINT)m_pBitmapInfoHeader->biWidth;

}

UINT CDib::GetHeight()

{

    return(UINT) m_pBitmapInfoHeader->biHeight;

}

UINT CDib::GetNumberOfColors()

{

    intnumberOfColors;

    if((m_pBitmapInfoHeader->biClrUsed == 0) &&

          (m_pBitmapInfoHeader->biBitCount< 9))

//biClrUsed表示實際用到的顏色數(shù),若0為2的biBitCount次中顏色

//biBitCount為用到的顏色的位數(shù),小于9則表示最大為8位,那么之多為256色

{

   switch (m_pBitmapInfoHeader->biBitCount)

   {

     case 1: numberOfColors = 2; break;

     case 4: numberOfColors = 16; break;

     case 8: numberOfColors = 256;

   }

}

   else

   numberOfColors = (int)m_pBitmapInfoHeader->biClrUsed;//若不是上面的情況,則直接返回顏色數(shù)

    return numberOfColors;

}

注意,由于調(diào)用了函數(shù)GlobalFreePtr以及GlobalAllocPtr,則需要在頭文件上添加相關(guān)的頭文件:

#include "windowsx.h"

下面來分析一下這段源代碼。其核心是LoadFile(),文件的讀取,看一下該類成員函數(shù)的定義

UINT GetNumberOfColors();//返回位圖顏色數(shù)目

UINT GetHeight();//返回位圖高度

UINT GetWidth();//返回位圖寬度

DWORD GetSize();//返回位圖文件大小

void LoadFile(const char*dibFileName);//文件的讀取操作

在LoadFile()函數(shù)中調(diào)用其他函數(shù)。

4.顯示圖像

顯示圖像當然要在View類中,因此圖像的顯示操作要在該類的OnDraw函數(shù)中進行

在該類中,我們要在菜單中點解“圖像顯示”按鈕,然后才顯示圖像,所以我們要先響應(yīng)菜單中“圖像顯示”命令。因此,右鍵“圖像顯示”,建立類向?qū)В?CTestView類中進行COMMAND響應(yīng),生成OnYuanTu函數(shù),代碼如下:

void CTestView::OnYuantu()

{

// TODO:Add your command handler code here

CTestDoc*pDoc = GetDocument();

ASSERT_VALID(pDoc);

   filename=pDoc->filename;//注意區(qū)分一下,雖然都是叫做filename但是不同,右邊這個filename是CTestDoc類的成員變量filename,存有文件的完整路徑,左邊這個是View類的filename

   state1=1;

Invalidate();//窗口重繪。當你的窗口需要重畫時,你需要用Invalidate()來使窗口無效,然后會調(diào)用OnDraw()就會重畫該窗口

}

當然,要在該類添加兩個變量state1和filename,類型為int和CString.分別用來做按下“圖像顯示”按鈕的標示,和存儲文件名。

接下來,在點擊“圖像顯示”按鈕之后,就要在OnDraw函數(shù)中顯示圖像了,代碼如下:

void CTestView::OnDraw(CDC* pDC)

{

//CTestDoc*pDoc = GetDocument();

//ASSERT_VALID(pDoc);

// TODO: add draw code for native datahere

if(state1==1)

{

   CBitmapm_bitmap;

     HBITMAPhBitmap=(HBITMAP)LoadImage(NULL,_T(filename),IMAGE_BITMAP,

0,0,LR_CREATEDIBSECTION|LR_DEFAULTSIZE|LR_LOADFROMFILE);

//LoadImage函數(shù)載入圖像,成功返回一個圖像句柄,第一個參數(shù)是實例的句柄,這里不需要,_T(filename)文件名,第三個參數(shù)指讀取的是位圖(還可以有光標,圖標),第四,第五個參數(shù)為0加上最后一個參數(shù)的|LR_DEFAULTSIZE,那么圖像的大小將由資源本身決定,LR_CREATEDIBSECTION:當?shù)谌齻€參數(shù)指定為IMAGE_BITMAP時,使得函數(shù)返回一個DIB部分位圖,而不是一個兼容的位圖。這個標志在裝載一個位圖,而不是映射它的顏色到顯示設(shè)備時非常有用。

        m_bitmap.Attach (hBitmap);

//Attach基本就是把一個句柄附加到一個mfc的對象上,比如你通過loadimage創(chuàng)建了一個handle,現(xiàn)在想用cbitmap類的成員函數(shù),你就可以聲明一個CBitmap對象,通過Attach將他們關(guān)聯(lián)在一起,以后就可以使用CBitmap的成員函數(shù)來操作hBitmap了

     CDC dcImage;

     if(!dcImage.CreateCompatibleDC (pDC))

      return;

    BITMAP bm;

     m_bitmap.GetBitmap(&bm);//得到CBitmap對象的信息(BITMAP結(jié)構(gòu)體),并存入那個參數(shù)(bm)中

        dcImage.SelectObject (&m_bitmap);

     pDC->BitBlt (0,0,bm.bmWidth,bm.bmHeight ,&dcImage,0,0,SRCCOPY);

}

}

5.運行程序

好了,運行程序吧,打開一幅位圖看看吧。呵呵

說明:

(1).GlobalFreePtr(m_pBitmapInfo);

GlobalFreePtr函數(shù)從定義上看:

#define    GlobalFreePtr(lp)                \

           (GlobalUnlockPtr(lp), (BOOL)GlobalFree(GlobalPtrHandle(lp)))

定義為GlobalUnlockPtr與GlobalFree函數(shù),

首先,其中GlobalFree函數(shù)為API函數(shù),作用是釋放指定內(nèi)存空間并使句柄無效。其參數(shù)為一個句柄,因此看GlobalPtrHandle(lp),這個函數(shù)被定義為

#define    GlobalPtrHandle(lp)         \

               ((HGLOBAL)GlobalHandle(lp))

那么看GlobalHandle函數(shù),作用是得到指針所指向內(nèi)存的相關(guān)的句柄,函數(shù)前的(HGLOBAL)意思也是強制轉(zhuǎn)換為句柄類型,注意看HGLOBAL的定義:

typedef HANDLE             HGLOBAL;

就是一個HANDLE而已。

接著看GlobalUnlockPtr函數(shù),定義為

#define     GlobalUnlockPtr(lp)      \

               GlobalUnlock(GlobalPtrHandle(lp))

GlobalUnlock作用是解除被鎖定的全局內(nèi)存對象,參數(shù)為一個句柄,用之前GlobalPtrHandle得到句柄。

綜上所述,可以看到GlobalFreePtr函數(shù)的作用就是解鎖內(nèi)存對象,釋放內(nèi)存并且使指針無效,通過多次定義,把幾個API函數(shù)整合到一個新的函數(shù)中,簡化操作而已。在這里,用途就是把m_pBitmapInfo指向的圖像的內(nèi)存與句柄釋放并無效,意思就是清空m_pBitmapInfo的內(nèi)容

(2)GlobalAllocPtr(GMEM_MOVEABLE,size)

通過查看定義發(fā)現(xiàn),與上面的函數(shù)類似

#define     GlobalAllocPtr(flags, cb)        \

               (GlobalLock(GlobalAlloc((flags), (cb))))

GlobalLock函數(shù)鎖定一個全局的內(nèi)存對象,返回指向該對象的第一個字節(jié)的指針,其參數(shù)為一個句柄,那么接著由GlobalAlloc來獲得句柄,GlobalAlloc函數(shù)是API函數(shù),作用是分配一個全局內(nèi)存塊,返回一個句柄,起參數(shù)flags,如本例為GMEM_MOVEABLE則為分配一個可移動內(nèi)存塊。第二個參數(shù)是分配的字符數(shù)size

綜上所述,該函數(shù)的功能就是先分配內(nèi)存,接著鎖定內(nèi)存塊,然后返回指針,可以用該指針來操作該內(nèi)存

小結(jié):這幾天的學(xué)習,總算明白了圖像打開以及顯示的大體思路以及操作方法,但在某些方面還是不太清楚,比如顯示方面,有關(guān)設(shè)備上下文的操作不是很清楚,還有加強學(xué)習,呵呵。整體的框架思路來源于《VC++圖像處理程序設(shè)計》這本書,特別感謝。希望大家指正。

參考資料:

《數(shù)字圖像處理編程入門》 清華大學(xué)出版社 呂鳳軍編著

《VC++圖像處理程序設(shè)計》清華大學(xué)出版社 楊淑瑩編著

《VC++深入詳解》 電子工業(yè)出版社 孫鑫編著

《新編Windows API參考大全》 電子工業(yè)出版社

《數(shù)字圖像處理基礎(chǔ)》 科學(xué)出版社 朱虹編著

本站僅提供存儲服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊舉報。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
有關(guān)VC知識的一些介紹_evan
【轉(zhuǎn)帖】常用斷點設(shè)置 & 常用斷點設(shè)置API函數(shù)原型
VC啟動一個新線程的三種方法
STM32單片機圖片解碼
數(shù)字圖像處理---構(gòu)造DIB類(一)
Visual C++中DDB與DIB位圖編程全攻略
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長圖 關(guān)注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點擊這里聯(lián)系客服!

聯(lián)系客服