• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            隨筆 - 42  文章 - 3  trackbacks - 0
            <2009年7月>
            2829301234
            567891011
            12131415161718
            19202122232425
            2627282930311
            2345678

            常用鏈接

            留言簿(2)

            隨筆檔案

            文章檔案

            網(wǎng)頁(yè)收藏

            搜索

            •  

            最新評(píng)論

            閱讀排行榜

            評(píng)論排行榜

            1.位圖和調(diào)色板的概念
            如今Windows(3.x以及95,NT)系列已經(jīng)成為決大多數(shù)用戶使用的操作系統(tǒng)。它比DOS成功的一個(gè)重要因素是它可視化的漂亮界面,例如你可以在桌面上鋪上你喜歡的墻紙。那么Windows是如何顯示圖象的呢?這就要談到位圖(Bitmap)。
            我們知道,普通的顯示器屏幕是由許許多多的點(diǎn)構(gòu)成的,我們稱(chēng)之為象素。顯示時(shí)采用掃描的方法:電子槍每次從左到右掃描一行,為每個(gè)象素著色,然后從上到下這樣掃描若干行,就掃過(guò)了一屏。為了防止閃爍,每秒要重復(fù)上述過(guò)程幾十次。例如我們常說(shuō)的屏幕分辨率為640*480,刷新頻率為70Hz,意思是說(shuō)每行要掃描640個(gè)象素,一共有480行,每秒重復(fù)掃描屏幕70次。我們稱(chēng)這種顯示器為位映象設(shè)備。所謂位映象,就是指一個(gè)二維的象素矩陣,而位圖就是采用位映象方法顯示和存儲(chǔ)的圖象。舉個(gè)例子,下圖1是一幅普通的黑白位圖,圖2是被放大后的圖,圖中每個(gè)方格代表了一個(gè)象素,我們可以看到:整個(gè)骷髏就是由這樣一些黑點(diǎn)和白點(diǎn)組成的。

                                         
            圖1.骷髏(左) 圖2.放大后的骷髏位圖(右)

            那么,彩色圖是怎么回事呢?
            我們先來(lái)說(shuō)說(shuō)三元色RGB概念。我們知道,自然界中的所有顏色都可以由紅,綠,藍(lán)(R,G,B)組合而成。有的顏色含有紅色成分多一些,如深紅;有的含有紅色成分少一些,如淡紅。針對(duì)含有紅色成分的多少,可以分成0到255共256個(gè)等級(jí),0級(jí)表示不含紅色成分,255級(jí)表示含有100%的紅色成分。同樣,綠色和藍(lán)色也被分成256級(jí)。這種分級(jí)的概念被稱(chēng)作量化。這樣,根據(jù)紅,綠,藍(lán)各種不同的組合我們就能表示出256*256*256,約1千6百萬(wàn)種顏色。這么多顏色對(duì)于我們?nèi)搜蹃?lái)已經(jīng)足夠了。
            下表是常見(jiàn)的一些顏色的RGB組合值。
            顏色RGB
            紅25500
            藍(lán)00255
            綠02550
            黃2552550
            紫2550255
            青0255255
            白255255255
            黑000
            灰128128128
            你大概已經(jīng)明白了,當(dāng)一幅圖中每個(gè)象素賦予不同的RGB值時(shí),就能呈現(xiàn)出五彩繽紛的顏色了,這樣就形成了彩色圖。對(duì),是這樣的,但實(shí)際上的做法還有些差別。
            讓我們來(lái)看看下面的例子。
            有一個(gè)長(zhǎng)寬各為200個(gè)象素,顏色數(shù)為16色的彩色圖,每一個(gè)象素都用R,G,B三個(gè)分量表示,因?yàn)槊總€(gè)分量有256個(gè)級(jí)別,要用8位(bit),即一個(gè)字節(jié)(byte)來(lái)表示,所以每個(gè)象素需要用3個(gè)字節(jié)。整個(gè)圖象要用200*200*3,約120k字節(jié),可不是一個(gè)小數(shù)目呀!如果我們用下面的方法,就能省的多。 因?yàn)槭且粋€(gè)16色圖,也就是說(shuō)這幅圖中最多只有16種顏色,我們可以用一個(gè)表:表中的每一行記錄一種顏色的R,G,B值。這樣當(dāng)我們表示一個(gè)象素的顏色時(shí),只需要指出該顏色是在第幾行,即該顏色在表中的索引值。舉個(gè)例子,如果表的第0行為255,0,0(紅色),那么當(dāng)某個(gè)象素為紅色時(shí),只需要標(biāo)明0即可。 讓我們?cè)賮?lái)計(jì)算一下:16種狀態(tài)可以用4位(bit)表示,所以一個(gè)象素要用半個(gè)字節(jié)。整個(gè)圖象要用200*200*0.5,約20k字節(jié),再加上表占用的字節(jié)為3*16=48字節(jié).整個(gè)占用的字節(jié)數(shù)約為前面的1/6,省很多吧。
            這張RGB的表,即是我們常說(shuō)的調(diào)色板(Palette),另一種叫法是顏色查找表LUT(LookUpTable),似乎更確切一些。Windows位圖中便用到了調(diào)色板技術(shù).其實(shí)是不光是Windows位圖,許多圖象文件格式如pcx,tif,gif等都用到了。所以很好地掌握調(diào)色板的概念是十分重要的.
            有一種圖,它的顏色數(shù)高達(dá)256*256*256種,也就是說(shuō)包含我們上述提到的R,G,B顏色表示方法中所有的顏色,這種圖叫做真彩色圖(TrueColor)。真彩色圖并不是說(shuō)一幅圖包含了所有的顏色,而是說(shuō)它具有顯示所有顏色的能力,即最多可以包含所有的顏色。表示真彩色圖時(shí),每個(gè)象素直接用R,G,B三個(gè)分量字節(jié)表示,而不采用調(diào)色板技術(shù),原因很明顯:如果用調(diào)色板,表示一個(gè)象素也要用24位,這是因?yàn)槊糠N顏色的索引要用24位(因?yàn)榭偣灿?的24次方種顏色,即調(diào)色板有2的24次方行),和直接用R,G,B三個(gè)分量表示用的字節(jié)數(shù)一樣,不但沒(méi)有任何便宜,還要加上一個(gè)256*256*256*3個(gè)字節(jié)的大調(diào)色板。所以真彩色圖直接用R,G,B三個(gè)分量表示,它又叫做24位色圖。

            2.Bmp文件格式
            介紹完位圖和調(diào)色板的概念,下面就讓我們來(lái)看一看Windows的位圖文件(.bmp文件)的格式是什么樣子的。 bmp文件大體上分成四個(gè)部分,如圖3所示。
             

            位圖文件頭BITMAPFILEHEADER

            位圖信息頭BITMAPINFOHEADER

            調(diào)色板Palette

            實(shí)際的位圖數(shù)據(jù)ImageDate


            圖3.Windows位圖文件結(jié)構(gòu)示意圖
            第一部分為位圖文件頭BITMAPFILEHEADER,是一個(gè)結(jié)構(gòu),其定義如下:
            typedefstructtagBITMAPFILEHEADER{
            WORD bfType;
            DWORD bfSize;
            WORD bfReserved1;
            WORD bfReserved2;
            DWORD bfOffBits;
            } BITMAPFILEHEADER;
            這個(gè)結(jié)構(gòu)的長(zhǎng)度是固定的,為14個(gè)字節(jié)(WORD為無(wú)符號(hào)16位整數(shù),DWORD為無(wú)符號(hào)32位整數(shù)),各個(gè)域的說(shuō)明如下:
            bfType
            指定文件類(lèi)型,必須是0x424D,即字符串"BM",也就是說(shuō)所有.bmp文件的頭兩個(gè)字節(jié)都是"BM"
            bfSize
            指定文件大小,包括這14個(gè)字節(jié)
            bfReserved1,bfReserved2
            為保留字,不用考慮
            bfOffBits
            為從文件頭到實(shí)際的位圖數(shù)據(jù)的偏移字節(jié)數(shù),即圖3中前三個(gè)部分的長(zhǎng)度之和。
            第二部分為位圖信息頭BITMAPINFOHEADER,也是一個(gè)結(jié)構(gòu),其定義如下:
            typedef struct tagBITMAPINFOHEADER{
            DWORD biSize;
            LONG biWidth;
            LONG biHeight;
            WORD biPlanes;
            WORD biBitCount;
            DWORD biCompression;
            DWORD biSizeImage;
            LONG biXPelsPerMeter;
            LONG biYPelsPerMeter;
            DWORD biClrUsed;
            DWORD biClrImportant;
            } BITMAPINFOHEADER; 這個(gè)結(jié)構(gòu)的長(zhǎng)度是固定的,為40個(gè)字節(jié)(WORD為無(wú)符號(hào)16位整數(shù),DWORD無(wú)符號(hào)32位整數(shù),LONG為32位整數(shù)),各個(gè)域的說(shuō)明如下:
            biSize
            指定這個(gè)結(jié)構(gòu)的長(zhǎng)度,為40
            biWidth
            指定圖象的寬度,單位是象素
            biHeight
            指定圖象的高度,單位是象素
            biPlanes
            必須是1,不用考慮
            biBitCount
            指定表示顏色時(shí)要用到的位數(shù),常用的值為1(黑白二色圖),4(16色圖),8(256色),24(真彩色圖)(新的.bmp格式支持32位色,這里就不做討論了)。
            biCompression
            指定位圖是否壓縮,有效的值為BI_RGB,BI_RLE8,BI_RLE4,BI_BITFIELDS(都是一些Windows定義好的常量)。要說(shuō)明的是,Windows位圖可以采用RLE4,和RLE8的壓縮格式,但用的不多。我們今后所討論的只有第一種不壓縮的情況,即biCompression為BI_RGB的情況。
            biSizeImage
            指定實(shí)際的位圖數(shù)據(jù)占用的字節(jié)數(shù),其實(shí)也可以從以下的公式中計(jì)算出來(lái):
            biSizeImage=biWidth'*biHeight
            要注意的是:上述公式中的biWidth'必須是4的整倍數(shù)(所以不是biWidth,而是biWidth',表示大于或等于biWidth的,離4最近的整倍數(shù)。舉個(gè)例子,如果biWidth=240,則biWidth'=240;如果biWidth=241,biWidth'=244)如果biCompression為BI_RGB,則該項(xiàng)可能為零
            biXPelsPerMeter
            指定目標(biāo)設(shè)備的水平分辨率,單位是每米的象素個(gè)數(shù),關(guān)于分辨率的概念,我們將在打印部分詳細(xì)介紹。
            biYPelsPerMeter
            指定目標(biāo)設(shè)備的垂直分辨率,單位同上。
            biClrUsed
            指定本圖象實(shí)際用到的顏色數(shù),如果該值為零,則用到的顏色數(shù)為2的biBitCount次方。
            biClrImportant
            指定本圖象中重要的顏色數(shù),如果該值為零,則認(rèn)為所有的顏色都是重要的。
            第三部分為調(diào)色板(Palette),當(dāng)然,這里是對(duì)那些需要調(diào)色板的位圖文件而言的。有些位圖,如真彩色圖,前面已經(jīng)講過(guò),是不需要調(diào)色板的,BITMAPINFOHEADER后直接是位圖數(shù)據(jù)。
            調(diào)色板實(shí)際上是一個(gè)數(shù)組,共有biClrUsed個(gè)元素(如果該值為零,則有2的biBitCount次方個(gè)元素)。數(shù)組中每個(gè)元素的類(lèi)型是一個(gè)RGBQUAD結(jié)構(gòu),占4個(gè)字節(jié),其定義如下:
            typedef struct tagRGBQUAD{
            BYTE rgbBlue; //該顏色的藍(lán)色分量
            BYTE rgbGreen; //該顏色的綠色分量
            BYTE rgbRed; //該顏色的紅色分量
            BYTE rgbReserved; //保留值
            } RGBQUAD;
            第四部分就是實(shí)際的圖象數(shù)據(jù)了。對(duì)于用到調(diào)色板的位圖,圖象數(shù)據(jù)就是該像素顏在調(diào)色板中的索引值,對(duì)于真彩色圖,圖象數(shù)據(jù)就是實(shí)際的R,G,B值。下面就2色,16色,256色位圖和真彩色位圖分別介紹。
            對(duì)于2色位圖,用1位就可以表示該像素的顏色(一般0表示黑,1表示白),所以一個(gè)字節(jié)可以表示8個(gè)像素。
            對(duì)于16色位圖,用4位可以表示一個(gè)像素的顏色,所以一個(gè)字節(jié)可以表示2個(gè)像素。
            對(duì)于256色位圖,一個(gè)字節(jié)剛好可以表示1個(gè)像素。
            對(duì)于真彩色圖,三個(gè)字節(jié)才能表示1個(gè)像素。
            要注意兩點(diǎn):
            1.每一行的字節(jié)數(shù)必須是4的整倍數(shù),如果不是,則需要補(bǔ)齊。這在前面介紹biSizeImage時(shí)已經(jīng)提到了。
            2.一般來(lái)說(shuō),.BMP文件的數(shù)據(jù)從下到上,從左到右的。也就是說(shuō),從文件中最先讀到的是圖象最下面一行的左邊第一個(gè)像素,然后是左邊第二個(gè)像素…接下來(lái)是倒數(shù)第二行左邊第一個(gè)像素,左邊第二個(gè)像素…依次類(lèi)推,最后得到的是最上面一行的最右一個(gè)像素。
            好了,終于介紹完bmp文件結(jié)構(gòu)了,是不是覺(jué)得頭有些大?別著急,對(duì)照著下面的程序,你就會(huì)很清楚了.

            3.顯示一個(gè)bmp文件的C程序
            下面的函數(shù)LoadBmpFile,其功能是從一個(gè).bmp文件中讀取數(shù)據(jù)(包括BITMAPINFOHEADER,調(diào)色板和實(shí)際圖象數(shù)據(jù))將其存儲(chǔ)在一個(gè)全局內(nèi)存句柄hImgData中,這個(gè)hImgData將在以后的圖象處理程序中用到。同時(shí)填寫(xiě)一個(gè)類(lèi)型為HBITMAP的全局變量hBitmap和一個(gè)類(lèi)型為HPALETTE的全局變量hPalette。這兩個(gè)變量將在處理WM_PAINT消息時(shí)用到,用來(lái)顯示出位圖。該函數(shù)的兩個(gè)參數(shù)分別是用來(lái)顯示位圖的窗口句柄,和.bmp文件名(全路徑),當(dāng)函數(shù)成功時(shí),返回TRUE,否則返回FALSE.
            BITMAPFILEHEADER bf;
            BITMAPINFOHEADER bi;
            BOOL LoadBmpFile(HWND hWnd,char* BmpFileName)
            {
            HFILE hf; //文件句柄
            LPBITMAPINFOHEADER lpImgData; //指向BITMAPINFOHEADER結(jié)構(gòu)的指針
            LOGPALETTE *pPal; //指向邏輯調(diào)色板結(jié)構(gòu)的指針
            LPRGBQUAD lpRGB; //指向RGBQUAD結(jié)構(gòu)的指針
            HPALETTE hPrevPalette;//用來(lái)保存設(shè)備中原來(lái)的調(diào)色板
            HDC hDc; //設(shè)備句柄
            HLOCAL hPal; //存儲(chǔ)調(diào)色板的局部?jī)?nèi)存句柄
            DWORD LineBytes; //每一行的字節(jié)數(shù)
            DWORD ImgSize; //實(shí)際的圖象數(shù)據(jù)占用的字節(jié)數(shù)
            DWORD NumColors; //實(shí)際用到的顏色數(shù),即調(diào)色板數(shù)組中的顏色個(gè)數(shù)
            DWORD i;

            if((hf=_lopen(BmpFileName,OF_READ))==HFILE_ERROR){
            MessageBox (hWnd,"Filec:\\test.bmpnotfound!","ErrorMessage",
            MB_OK|MB_ICONEXCLAMATION);
            return FALSE;//打開(kāi)文件錯(cuò)誤,返回
            }
            //將BITMAPFILEHEADER結(jié)構(gòu)從文件中讀出,填寫(xiě)到bf中
            _lread(hf,(LPSTR)&bf,sizeof(BITMAPFILEHEADER));
            //將BITMAPINFOHEADER結(jié)構(gòu)從文件中讀出,填寫(xiě)到bi中
            _lread(hf,(LPSTR)&bi,sizeof(BITMAPINFOHEADER));

            /*我們定義了一個(gè)宏#define WIDTHBYTES(i) ((i+31)/32*4),上面曾經(jīng)提到過(guò),每一行的字節(jié)數(shù)必須是4的整倍數(shù),只要調(diào)用WIDTHBYTES(bi.biWidth*bi.biBitCount)就能完成這一換算.舉一個(gè)例子,對(duì)于2色圖,如果圖象寬是31,則每一行需要31位存儲(chǔ),合3個(gè)字節(jié)加7位,因?yàn)樽止?jié)數(shù)必須是4的整倍數(shù),所以應(yīng)該是4,而此時(shí)的biWidth=31,biBitCount=1,WIDTHBYTES(31*1)=4,和我們?cè)O(shè)想的一樣。再舉一個(gè)256色的例子,如果圖象寬是31,則每一行需要31個(gè)字節(jié)存儲(chǔ),因?yàn)樽止?jié)數(shù)必須是4的整倍數(shù),所以應(yīng)該是32,而此時(shí)的biWidth=31,biBitCount=8,WIDTHBYTES(31*8)=32,和我們?cè)O(shè)想的一樣。你可以多舉幾個(gè)例子來(lái)驗(yàn)證一下*/
            //LineBytes為每一行的字節(jié)數(shù)
            LineBytes=(DWORD)WIDTHBYTES(bi.biWidth*bi.biBitCount);
            //ImgSize為實(shí)際的圖象數(shù)據(jù)占用的字節(jié)數(shù)
            ImgSize=(DWORD)LineBytes*bi.biHeight;
            //NumColors為實(shí)際用到的顏色數(shù),即調(diào)色板數(shù)組中的顏色個(gè)數(shù)
            if(bi.biClrUsed!=0)
            NumColors=(DWORD)bi.biClrUsed;//如果bi.biClrUsed不為零,就是本圖象實(shí)際
            //用到的顏色數(shù)
            else//否則,用到的顏色數(shù)為2的biBitCount次方。
            switch(bi.biBitCount){
            case1:
            NumColors=2;
            break;
            case4:
            NumColors=16;
            break;
            case8:
            NumColors=256;
            break;
            case24:
            NumColors=0;//對(duì)于真彩色圖,沒(méi)用到調(diào)色板
            break;
            default:
            //不處理其它的顏色數(shù),認(rèn)為出錯(cuò)。
            MessageBox(hWnd,"Invalidcolornumbers!","ErrorMessage",
            MB_OK|MB_ICONEXCLAMATION);
            _lclose(hf);
            return FALSE;//關(guān)閉文件,返回FALSE
            }
            if(bf.bfOffBits!=(DWORD)(NumColors*sizeof(RGBQUAD)+sizeof(BITMAPFILEHEADER)
            +sizeof(BITMAPINFOHEADER)))
            {
            //計(jì)算出的偏移量與實(shí)際偏移量不符,一定是顏色數(shù)出錯(cuò)
            MessageBox(hWnd,"Invalidcolornumbers!","ErrorMessage",
            MB_OK|MB_ICONEXCLAMATION);
            _lclose(hf);
            return FALSE;//關(guān)閉文件,返回FALSE
            }
            bf.bfSize=sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)+NumColors
            *sizeof(RGBQUAD)+ImgSize;
            //分配內(nèi)存,大小為BITMAPINFOHEADER結(jié)構(gòu)長(zhǎng)度加調(diào)色板+實(shí)際位圖數(shù)據(jù)
            if((hImgData=GlobalAlloc(GHND,(DWORD)(sizeof(BITMAPINFOHEADER)+
            NumColors*sizeof(RGBQUAD)+ImgSize)))==NULL)
            {
            //分配內(nèi)存錯(cuò)誤
            MessageBox(hWnd,"Errorallocmemory!","ErrorMessage",
            MB_OK|MB_ICONEXCLAMATION);
            _lclose(hf);
            return FALSE;//關(guān)閉文件,返回FALSE
            }
            //指針lpImgData指向該內(nèi)存區(qū)
            lpImgData=(LPBITMAPINFOHEADER)GlobalLock(hImgData);

            //文件指針重新定位到BITMAPINFOHEADER開(kāi)始處
            _llseek(hf,sizeof(BITMAPFILEHEADER),SEEK_SET);
            //將文件內(nèi)容讀入lpImgData
            _hread(hf,(char*)lpImgData,(long)sizeof(BITMAPINFOHEADER)
            +(long)NumColors*sizeof(RGBQUAD)+ImgSize);
            _lclose(hf);//關(guān)閉文件

            if(NumColors!=0) //NumColors不為零,說(shuō)明用到了調(diào)色板
            {
            //為邏輯調(diào)色板分配局部?jī)?nèi)存,大小為邏輯調(diào)色板結(jié)構(gòu)長(zhǎng)度加NumColors個(gè)
            //PALETTENTRY大小
            hPal=LocalAlloc(LHND,sizeof(LOGPALETTE)+NumColors*sizeof(PALETTEENTRY));

            //指針pPal指向該內(nèi)存區(qū)
            pPal=(LOGPALETTE*)LocalLock(hPal);

            //填寫(xiě)邏輯調(diào)色板結(jié)構(gòu)的頭
            pPal->palNumEntries=NumColors;
            pPal->palVersion=0x300;

            //lpRGB指向的是調(diào)色板開(kāi)始的位置
            lpRGB=(LPRGBQUAD)((LPSTR)lpImgData+(DWORD)sizeof(BITMAPINFOHEADER));

            //填寫(xiě)每一項(xiàng)
            for(i=0;i<NumColors;i++)
            {
            pPal->palPalEntry[i].peRed=lpRGB->rgbRed;
            pPal->palPalEntry[i].peGreen=lpRGB->rgbGreen;
            pPal->palPalEntry[i].peBlue=lpRGB->rgbBlue;
            pPal->palPalEntry[i].peFlags=(BYTE)0;
            lpRGB++;//指針移到下一項(xiàng)
            }

            //產(chǎn)生邏輯調(diào)色板,hPalette是一個(gè)全局變量
            hPalette=CreatePalette(pPal);

            //釋放局部?jī)?nèi)存
            LocalUnlock(hPal);
            LocalFree(hPal);
            }

            //獲得設(shè)備上下文句柄
            hDc=GetDC(hWnd);

            if(hPalette)//如果剛才產(chǎn)生了邏輯調(diào)色板
            {
            //將新的邏輯調(diào)色板選入DC,將舊的邏輯調(diào)色板句柄保存在hPrevPalette
            hPrevPalette=SelectPalette(hDc,hPalette,FALSE);
            RealizePalette(hDc);
            }

            //產(chǎn)生位圖句柄
            hBitmap=CreateDIBitmap(hDc, (LPBITMAPINFOHEADER)lpImgData,(LONG)CBM_INIT,
            (LPSTR)lpImgData+sizeof(BITMAPINFOHEADER)+NumColors*sizeof(RGBQUAD),
            (LPBITMAPINFO)lpImgData,DIB_RGB_COLORS);

            //將原來(lái)的調(diào)色板(如果有的話)選入設(shè)備上下文句柄
            if(hPalette&&hPrevPalette)
            {
            SelectPalette(hDc,hPrevPalette,FALSE);
            RealizePalette(hDc);
            }

            ReleaseDC(hWnd,hDc); //釋放設(shè)備上下文
            GlobalUnlock(hImgData); //解鎖內(nèi)存區(qū)
            Return TRUE; //成功返回
            }

            上面的程序中,要說(shuō)明的有兩點(diǎn):
            第一,對(duì)于需要調(diào)色板的圖,要想正確的顯示,必須根據(jù).bmp文件,產(chǎn)生邏輯調(diào)色板。產(chǎn)生的方法是:1.為邏輯調(diào)色板指針?lè)峙鋬?nèi)存,大小為邏輯調(diào)色板結(jié)構(gòu)(LOGPALETTE)長(zhǎng)度加NumColors個(gè)PALETTENTRY大小。(調(diào)色板的每一項(xiàng)都是一個(gè)PALETTEENTRY結(jié)構(gòu)),2.填寫(xiě)邏輯調(diào)色板結(jié)構(gòu)的頭pPal->palNumEntries=NumColors;pPal->palVersion=0x300;3.從文件中讀取調(diào)色板的RGB值,填寫(xiě)到每一項(xiàng)中。4,產(chǎn)生邏輯調(diào)色板:hPalette=CreatePalette(pPal)
            第二,產(chǎn)生位圖(BITMAP)句柄,該項(xiàng)工作由函數(shù)CreateDIBitmap來(lái)完成。hBitmap=CreateDIBitmap(hDc,LPBITMAPINFOHEADER)lpImgData,(LONG)CBM_INIT, (LPSTR)lpImgData+sizeof(BITMAPINFOHEADER)+NumColors*sizeof(RGBQUAD), (LPBITMAPINFO)lpImgData,DIB_RGB_COLORS); CreateDIBitmap的作用是產(chǎn)生一個(gè)和Windows設(shè)備無(wú)關(guān)的位圖。該函數(shù)的第一項(xiàng)參數(shù)為設(shè)備上下文句柄,如果位圖用到了調(diào)色板,要在調(diào)用CreateDIBitmap之前將邏輯調(diào)色板選入該設(shè)備上下文中,產(chǎn)生hBitmap后,再把原調(diào)色板選入該設(shè)備上下文中,并釋放該上下文;第二項(xiàng)為指向BITMAPINFOHEADER的指針;第三項(xiàng)就用常量CBM_INI,不用考慮;第四項(xiàng)為指向調(diào)色板的指針;第五項(xiàng)為指向BITMAPINFO(包括BITMAPINFOHEADER,調(diào)色板,及實(shí)際的圖象數(shù)據(jù))的指針;第六項(xiàng)就用常量DIB_RGB_COLORS,不用考慮。
            上面提到了設(shè)備上下文,相信編過(guò)Windows程序的讀者對(duì)它并不陌生,這里再簡(jiǎn)單的介紹一下。Windows操作系統(tǒng)統(tǒng)一管理著諸如顯示,打印等操作,將它們看作是一個(gè)個(gè)的設(shè)備,每一個(gè)設(shè)備都有一個(gè)復(fù)雜的數(shù)據(jù)結(jié)構(gòu)來(lái)維護(hù)。所謂設(shè)備上下文就是指這個(gè)數(shù)據(jù)結(jié)構(gòu)。然而,我們不能直接和這些設(shè)備上下文打交道,只能通過(guò)引用標(biāo)識(shí)它的句柄(實(shí)際上是一個(gè)整數(shù)),讓W(xué)indows去做相應(yīng)的處理。產(chǎn)生的邏輯調(diào)色板句柄hPalette和位圖句柄hBitmap要在處理WM_PAINT消息時(shí)使用,這樣才能在屏幕上顯示出來(lái),處理過(guò)程如下面的程序。

            StaticHDC hDC,hMemDC;
            PAINTSTRUCT ps;

            case WM_PAINT:
            {
            hDC=BeginPaint(hwnd,&ps);//獲得屏幕設(shè)備上下文
            if(hBitmap)//hBitmap一開(kāi)始是NULL,當(dāng)不為NULL時(shí)表示有圖
            {
            hMemDC=CreateCompatibleDC(hDC);//建立一個(gè)內(nèi)存設(shè)備上下文
            if(hPalette)//有調(diào)色板
            {
            //將調(diào)色板選入屏幕設(shè)備上下文
            SelectPalette(hDC,hPalette,FALSE);
            //將調(diào)色板選入內(nèi)存設(shè)備上下文
            SelectPalette(hMemDC,hpalette,FALSE);
            RealizePalette(hDC);
            }
            //將位圖選入內(nèi)存設(shè)備上下文
            SelectObject(hMemDC,hBitmap);
            //顯示位圖
            BitBlt(hDC,0,0,bi.biWidth,bi.biHeight,hMemDC,0,0,SRCCOPY);
            //釋放內(nèi)存設(shè)備上下文
            DeleteDC(hMemDC);
            }
            //釋放屏幕設(shè)備上下文
            EndPaint(hwnd,&ps);
            break;
            }

            在上面的程序中,我們調(diào)用CreateCompatibleDC創(chuàng)建一個(gè)內(nèi)存設(shè)備上下文。SelectObject函數(shù)將于設(shè)備無(wú)關(guān)的位圖選入內(nèi)存設(shè)備上下文中。然后我們調(diào)用BitBlt函數(shù)在內(nèi)存設(shè)備上下文和屏幕設(shè)備上下文中進(jìn)行位拷貝。由于所有操作都是在內(nèi)存中進(jìn)行,所以是最快的。
            BitBlt函數(shù)的參數(shù)分別為:1.目標(biāo)設(shè)備上下文,在上面的程序里,為屏幕設(shè)備上下文,如果改成打印設(shè)備上下文,就不是顯示位圖,而是打印;2.目標(biāo)矩形左上角點(diǎn)x坐標(biāo);3.目標(biāo)矩形左上角點(diǎn)y坐標(biāo),在上面的程序中,2和3為(0,0),表示顯示在窗口的左上角;4.目標(biāo)矩形的寬度;5.目標(biāo)矩形的高度;6.源設(shè)備上下文,在上面的程序里,為內(nèi)存設(shè)備上下文;7.源矩形左上角點(diǎn)x坐標(biāo);8.源矩形左上角點(diǎn)y坐標(biāo);9.操作方式,在這里為SRCCOPY,表示直接將源矩形拷貝到目標(biāo)矩形。還可以是反色,擦除,做"與"運(yùn)算等操作,具體細(xì)節(jié)見(jiàn)VC++幫助。你可以試著改改第2,3,4,5,7,8,9項(xiàng)參數(shù),就能體會(huì)到它們的含義了。
            終于講完了。是不是覺(jué)得有點(diǎn)枯燥?這一講是有點(diǎn)兒枯燥,特別是當(dāng)你對(duì)Windows的編程并不很清楚時(shí),就更覺(jué)得如此。不過(guò),當(dāng)一幅漂亮的bmp圖顯示在屏幕上時(shí),你還是會(huì)興奮的大叫"Yeah",至少當(dāng)年我是這樣。

            最后,再介紹一個(gè)命令行編譯的竅門(mén)。為什么要用命令行編譯呢?主要有兩個(gè)好處:
            第一,不用進(jìn)入IDE(集成開(kāi)發(fā)環(huán)境),節(jié)省了時(shí)間,而且編譯速度也比較快。
            第二,對(duì)于簡(jiǎn)單的程序,不用生成項(xiàng)目文件.mdp或.mak,直接就能生成.exe文件,這一點(diǎn),在下面的例子中可以看到。
            在安裝VisualC++完畢時(shí),在bin目錄下會(huì)產(chǎn)生一個(gè)VCVARS32.BAT文件,它的作用是在命令行編譯時(shí)設(shè)置正確的環(huán)境變量,如存放頭文件的INCLUDE目錄,存放庫(kù)文件的LIB目錄等,如果你沒(méi)找到這個(gè)批處理文件,可以參考下面的例子,自己做一個(gè)批處理。

            @echo off
            set MSDevDir=d:\MSDEV
            set VcOsDir=WIN95
            set PATH="%MSDevDir%\BIN";"%MSDevDir%\BIN\%VcOsDir%";"%PATH%"
            set INCLUDE=%MSDevDir%\INCLUDE;%MSDevDir%\MFC\INCLUDE;%INCLUDE%
            set LIB=%MSDevDir%\LIB;%MSDevDir%\MFC\LIB;%LIB%
            set VcOsDir=

            只要把上面的"d:\MSDEV"改成你自己的VC目錄就可以了。在DOSPROMPT下執(zhí)行該批處理文件,執(zhí)行set命令,你就能看到新設(shè)置的環(huán)境變量了。如下所示:
            PATH=D:\MSDEV\BIN;D:\MSDEV\BIN\WIN95;C:\WIN95;C:\WIN95\COMMAND;C:\WIN95\SYSTEM;
            INCLUDE=d:\msdev\INCLUDE;d:\msdev\MFC\INCLUDE;
            LIB=d:\msdev\LIB;d:\msdev\MFC\LIB;
            現(xiàn)在我們就可以進(jìn)行命令行編譯了。(當(dāng)然,你也可以使用IDE,先new一個(gè)project,然后把.c和.rc文件插入到project中,編譯運(yùn)行。)
            首先編譯資源文件,輸入rc bmp.rc,將生成bmp.res文件,接著輸入cl bmp.c bmp.res user32.lib gdi32.lib,就生成bmp.exe了。可以看到,我們并沒(méi)有用到項(xiàng)目文件,所以,對(duì)于這種簡(jiǎn)單的程序來(lái)說(shuō),使用命令行編譯還是非常方便的。好了,運(yùn)行bmp.exe,欣賞一下你今天的勞動(dòng)成果。

            注意事項(xiàng):
            命令行編譯過(guò)程如下:
            vcvars32
            rc bmp.rc
            cl bmp.c bmp.res user32.lib gdi32.lib

             ========
            后來(lái)發(fā)現(xiàn)原文出自
            http://vipbase.net/ipbook/此書(shū)是清華學(xué)生寫(xiě)的,做圖像編程的入門(mén)教材很不錯(cuò)!

            posted on 2009-07-10 22:59 鷹擊長(zhǎng)空 閱讀(1181) 評(píng)論(0)  編輯 收藏 引用

            只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。
            網(wǎng)站導(dǎo)航: 博客園   IT新聞   BlogJava   博問(wèn)   Chat2DB   管理


            久久婷婷五月综合国产尤物app| 无码人妻精品一区二区三区久久久 | 日韩人妻无码一区二区三区久久 | 久久国产成人午夜AV影院| 久久久久久久尹人综合网亚洲| 亚洲国产精品久久久久婷婷软件 | 久久五月精品中文字幕| 噜噜噜色噜噜噜久久| 精品久久8x国产免费观看| 欧美777精品久久久久网| 久久久久99精品成人片三人毛片| 午夜视频久久久久一区| AV无码久久久久不卡网站下载| 精品久久久久中文字| 久久精品水蜜桃av综合天堂| 久久精品国产清自在天天线| 一本一道久久综合狠狠老 | 日韩人妻无码精品久久久不卡| 久久青青草原精品影院| 久久久久久精品成人免费图片| 久久91精品久久91综合| 97精品伊人久久久大香线蕉| 久久香蕉国产线看观看99| 人妻久久久一区二区三区| 激情久久久久久久久久| 国产精品天天影视久久综合网| 久久久午夜精品福利内容| 久久久久九国产精品| 国产精品久久久久久搜索| 久久亚洲AV成人出白浆无码国产| 亚洲va久久久久| 深夜久久AAAAA级毛片免费看| 国产99久久久久久免费看| 久久亚洲国产午夜精品理论片| 久久免费的精品国产V∧| 亚洲欧美成人综合久久久| 久久精品一本到99热免费| 日本五月天婷久久网站| 久久精品综合网| 超级碰碰碰碰97久久久久| 久久久久久久久久久|