• <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>
            幽幽
             
            posts - 51,  comments - 28,  trackbacks - 0
            一、 簡介

            屏幕抓圖程序在處理圖形中應(yīng)用廣泛。作為Windows XP及以后版本操作系統(tǒng)的圖形處理內(nèi)核,GDI+在二維幾何圖形處理、圖像顯示與轉(zhuǎn)換和字符排版等方面簡直是傳統(tǒng)GDI程序員的一種解脫。但是,至少在目前情況下,GDI+尚不能完全代替GDI。與GDI相比,它至少還存在以下不足:

            不支持從內(nèi)存到屏幕的位傳輸操作;

            不支持光柵“位運(yùn)算”操作;

            如果程序性能、速度要求比較嚴(yán)格,在圖片輸出方面的表現(xiàn)較差時(shí),GDI往往能取代實(shí)現(xiàn)高性能的輸出。

            本文通過對流行的屏幕抓圖程序工作原理的剖析,力圖向讀者闡明GDI+與GDI各自在圖形處理方面的優(yōu)缺點(diǎn),并給出相應(yīng)的VC++ .NET代碼實(shí)現(xiàn)。

                二、 GDI在抓圖中的關(guān)鍵作用

                要實(shí)現(xiàn)屏幕抓圖,關(guān)鍵有兩點(diǎn):一是獲取圖片所在窗口的窗口句柄,即在何處捕獲圖片;二是保存抓取的圖片,實(shí)現(xiàn)這一點(diǎn)正是GDI+的強(qiáng)項(xiàng)。

                對于問題一,可以利用SetCapture函數(shù),它能夠追蹤鼠標(biāo)指針的移動(dòng)(包括在屏幕抓圖程序窗口之外的窗口)。在移動(dòng)鼠標(biāo)的過程中,它還可以根據(jù)鼠標(biāo)的指針?biāo)谖恢脕砼袛喈?dāng)前窗口的窗口句柄。我們還可以使用函數(shù)WindowFromPoint,這個(gè)函數(shù)能夠找出鼠標(biāo)指針當(dāng)前位置所對應(yīng)的窗口句柄。

                使用過知名的抓圖軟件SnagIT的讀者都知道,在選擇抓圖窗口時(shí),鼠標(biāo)指針?biāo)谖恢玫拇翱诙紩霈F(xiàn)加粗的紅色邊框,以提醒目前所選擇的窗口,這個(gè)功能實(shí)現(xiàn)起來有些復(fù)雜。下面介紹在GDI中如何使這個(gè)紅色邊框出現(xiàn)。

                【注意】正是由于這個(gè)紅色邊框的實(shí)現(xiàn),讀者才能發(fā)現(xiàn)GDI+在這方面的弱點(diǎn)。

            在GDI中,一個(gè)最基本的概念就是設(shè)備環(huán)境(DC),每一個(gè)窗口都具有自己的DC。如果能夠找到窗口的DC,那么,用戶就能夠在該窗口的任何位置繪圖。然而,在屏幕抓圖程序中,由于用戶所選擇的窗口不固定,所以,要想得到鼠標(biāo)指針?biāo)幋翱诘腄C并不容易。這一問題的答案在于GetDC函數(shù)。下面是GetDC的函數(shù)聲明:

            HDC GetDC(HWND hWnd);

                這里,hWnd是DC對應(yīng)的窗口句柄。注意,當(dāng)hWnd為空時(shí),該函數(shù)返回的是整個(gè)屏幕的設(shè)備環(huán)境句柄。這就意味著,開發(fā)人員可以在屏幕上的任何位置進(jìn)行任意的繪圖操作。

                在鼠標(biāo)指針?biāo)幍拇翱诶L圖時(shí),繪圖的目的只是為了提醒用戶目前所選擇的窗口,所以,在繪圖時(shí),必須保證不會破壞窗口原有的畫面。這時(shí)可將窗口的繪圖模式設(shè)為RS_NOTXORPEN,將畫筆顏色與屏幕顏色進(jìn)行異或運(yùn)算之后,再對屏幕顏色取反即可。RS_NOTXORPEN運(yùn)算方式的特點(diǎn)在于:對同一像素進(jìn)行兩次RS_NOTXORPEN運(yùn)算后,像素值并不會發(fā)生變化。這樣,在同一個(gè)地方進(jìn)行兩次繪圖后,窗口的畫面并不會發(fā)生任何變化。

                【注意】這些功能在GDI+中很難實(shí)現(xiàn)。

                三、 編碼實(shí)現(xiàn)

            由上可知,屏幕抓圖至少分為3個(gè)步驟:

                (1) 啟用鼠標(biāo)指針捕獲。

                (2) 在鼠標(biāo)指針?biāo)谔幍拇翱谶M(jìn)行繪圖,提示抓圖的目標(biāo)。

                (3) 選定目標(biāo)窗口時(shí),將目標(biāo)窗口的畫面保存為自定義的位圖并終止鼠標(biāo)指針捕獲。

                以下是具體的編程步驟:

                (1)在Visual C++ .NET中按照GDI+程序的框架新建一個(gè)基于對話框的項(xiàng)目ScreenCapture,然后準(zhǔn)備好一個(gè)外形為相機(jī)的光標(biāo)文件(*.cur),將之引入資源管理器(IDC_CAMERA)。接著在CScreenCaptureDlg類中加入以下兩個(gè)全局變量:

            HWND hwndCapture;

            Crect rectCapture;

               (2)通過類向?qū)Ъ尤雽M_M(jìn)OUSEMOVE及WM_LBUTTONUP事件的響應(yīng)函數(shù),分別如下所示。

            void CScreenCaptureDlg::OnMouseMove(UINT nFlags, CPoint point)

            {

            //如果用戶按隹鼠標(biāo)左鍵不放,則開始抓取圖片

            if(nFlags==MK_LBUTTON){

            //隱藏程序窗口,以免影響在抓取時(shí)的“視野”

            ShowWindow(SW_HIDE);

            //載入“照相機(jī)”鼠標(biāo)指針,開始追蹤鼠標(biāo)指針的移動(dòng)

            HCURSOR cur=LoadCursor(AfxGetInstanceHandle(),MAKEINTRESOURCE(IDC_CAMERA));

            SetCursor(cur);

            SetCapture();

            //獲得鼠標(biāo)指針?biāo)诖翱诘木浔?br>
            this->ClientToScreen(&point);

            hwndCapture=(HWND)::WindowFromPoint(point);

            //取得屏幕的設(shè)備環(huán)境句柄,以便在屏幕的任何位置繪圖

            HDC hDC=::GetDC(NULL);

            //建立一個(gè)紅色的畫筆

            HPEN hPen=CreatePen(PS_INSIDEFRAME,6,RGB(255,0,0));

            //將繪圖模式設(shè)為R2_NOTXORPEN,在繪圖時(shí)可以不破壞原有的背景

            int nMode=SetROP2(hDC,R2_NOTXORPEN);

            HPEN hpenOld=(HPEN)SelectObject(hDC,hPen);

            //得到鼠標(biāo)指針?biāo)诖翱诘膮^(qū)域

            ::GetWindowRect(hwndCapture,&rectCapture);

            //在鼠標(biāo)指針?biāo)谔幍拇翱谒闹墚嬕患t色的矩形,做為選定時(shí)的提示

            POINT pt[5];

            pt[0]=CPoint(rectCapture.left,rectCapture.top);

            pt[1]=CPoint(rectCapture.right,rectCapture.top);

            pt[2]=CPoint(rectCapture.right,rectCapture.bottom);

            pt[3]=CPoint(rectCapture.left,rectCapture.bottom);

            pt[4]=CPoint(rectCapture.left,rectCapture.top);

            ::Polyline(hDC,pt,5);

            //延時(shí)后再重繪紅色矩形,這樣不會破壞原有的內(nèi)容

            Sleep(100);

            ::Polyline(hDC,pt,5);

            ::SelectObject(hDC,hpenOld);

            ::ReleaseDC(NULL,hDC);

            }

            CDialog::OnMouseMove(nFlags, point);

            }

            void CScreenCaptureDlg::OnLButtonUp(UINT nFlags, CPoint point)

            {

            // 得到鼠標(biāo)指針?biāo)诖翱诘膮^(qū)域?qū)挕⒏?br>
            int nWidth=rectCapture.Width();

            int nHeight=rectCapture.Height();

            HDC hdcScreen,hMemDC;

            HBITMAP hBitmap,hOldBitmap;

            //建立一個(gè)屏幕設(shè)備環(huán)境句柄

            hdcScreen=CreateDC("DISPLAY",NULL,NULL,NULL);

            hMemDC=CreateCompatibleDC(hdcScreen);

            //建立一個(gè)與屏幕設(shè)備環(huán)境句柄兼容、與鼠標(biāo)指針?biāo)诖翱诘膮^(qū)域等大的位圖

            hBitmap=CreateCompatibleBitmap(hdcScreen,nWidth,nHeight);

            //把新位圖選到內(nèi)存設(shè)備描述表中

            hOldBitmap=(HBITMAP)SelectObject(hMemDC,hBitmap);

            //把屏幕設(shè)備描述表拷貝到內(nèi)存設(shè)備描述表中

            BitBlt(hMemDC,0,0,nWidth,nHeight,hdcScreen,rectCapture.left,rectCapture.top,SRCCOPY);

            DeleteDC(hdcScreen);

            DeleteDC(hMemDC);

            //返回位圖句柄

            //打開剪貼板,并將位圖拷到剪貼板上

            OpenClipboard();

            EmptyClipboard();

            SetClipboardData(CF_BITMAP,hBitmap);

            //關(guān)閉剪貼板

            CloseClipboard();

            MessageBox("屏幕內(nèi)容已經(jīng)拷到剪貼板!");

            ReleaseCapture();

            //恢復(fù)窗口顯示模式

            ShowWindow(SW_NORMAL);

            CDialog::OnLButtonUp(nFlags, point);

            }

                至此,一個(gè)具有專業(yè)效果的屏幕抓圖程序的核心已經(jīng)搞定。

                四、 用GDI+實(shí)現(xiàn)畫面的保存

                經(jīng)過上面兩步,如果用戶在對話框中按住鼠標(biāo)左鍵不放,程序便開始“抓圖”。當(dāng)選擇好抓圖的目標(biāo)后,松開鼠標(biāo)左鍵,抓圖的目標(biāo)窗口的畫面就自動(dòng)保存到剪貼板中了。但是,把畫面保存到文件中更為重要。如果用GDI的方式來操作,需要對各種類位圖的結(jié)構(gòu)有詳盡的了解,極其麻煩。但如果用GDI+來實(shí)現(xiàn)之則極為容易。下面介紹如何將已經(jīng)抓到的圖片保存到一個(gè)BMP文件中。

            由上面知,抓圖程序已經(jīng)得到了所捕獲的窗口的位圖句柄,接下來要將位圖句柄保存為相應(yīng)的位圖文件。這一切歸功于GDI+的Bitmap類,詳見下列代碼。

            void CScreenCaptureDlg::OnLButtonUp(UINT nFlags, CPoint point)

            {

            //……省略

            if(GetSaveFileName(&ofn))

            {

            CLSID pngClsid;

            Bitmap bmp(hBitmap,NULL);

            //獲取BMP文件的編碼方式

            GetEncoderClsid(L"image/bmp",&pngClsid);//幫助函數(shù)

            CString tmp(ofn.lpstrFile);

            CStringW filename((LPCSTR)tmp);

            //保存所截取的屏幕圖片

            bmp.Save(filename,&pngClsid);

            }

            ReleaseCapture();

            MessageBox("屏幕內(nèi)容已經(jīng)保存到文件中!");

            //恢復(fù)窗口顯示模式

            ShowWindow(SW_NORMAL);

            CDialog::OnLButtonUp(nFlags, point);

            }

                五、 小結(jié)

                本文通過一個(gè)專業(yè)的屏幕抓圖程序的核心實(shí)現(xiàn),對比分析了GDI與GDI+各自的優(yōu)缺點(diǎn)。但我們相信,GDI+作為新一代圖形引擎,隨著版本的不斷升級,其遲早要淘汰掉GDI。本人拙見,不足處還望讀者指正。

            另外,本文源碼在Windows 2000/VC++.NET 2003環(huán)境中調(diào)試通過。調(diào)試過程中注意:

            確保工程對GDI+庫的正確引用:在頭文件stdafx.h中要加入相應(yīng)引用;在應(yīng)用程序類的InitInstance成員函數(shù)前后及其析構(gòu)函數(shù)中加適當(dāng)?shù)牟僮鳎还こ叹幾g時(shí)要加入對gdiplus.lib的引用(“項(xiàng)目”|“添加現(xiàn)有項(xiàng)”,我的機(jī)器上是在C:\Program Files\Microsoft Visual Studio.NET\vc7\platformSDK\lib下找到庫文件)。

             

            posted on 2008-08-13 23:02 幽幽 閱讀(2026) 評論(0)  編輯 收藏 引用

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



            <2008年12月>
            30123456
            78910111213
            14151617181920
            21222324252627
            28293031123
            45678910

            常用鏈接

            留言簿(6)

            隨筆分類(35)

            隨筆檔案(51)

            文章分類(3)

            文章檔案(3)

            相冊

            我的鏈接

            搜索

            •  

            最新評論

            閱讀排行榜

            評論排行榜

            99久久www免费人成精品| 性做久久久久久久久老女人| 人妻少妇久久中文字幕| 国产成人精品免费久久久久| 97久久精品国产精品青草| 91精品免费久久久久久久久| 亚洲欧美一级久久精品| 99久久免费国产精品热| 一本久久精品一区二区| 2020久久精品国产免费| 一本久久免费视频| 国产精品狼人久久久久影院| 亚洲国产精品无码成人片久久| 夜夜亚洲天天久久| 日本人妻丰满熟妇久久久久久| 理论片午午伦夜理片久久| 成人久久精品一区二区三区| 欧美性大战久久久久久| 亚洲精品高清久久| 国产精品久久永久免费| 人妻无码久久一区二区三区免费| 欧美性大战久久久久久| 国产成人无码精品久久久免费 | 久久天天婷婷五月俺也去| 亚洲综合久久综合激情久久| 久久亚洲AV成人出白浆无码国产| 色妞色综合久久夜夜| 久久久噜噜噜久久| 久久亚洲综合色一区二区三区| 亚洲va久久久噜噜噜久久| 日本五月天婷久久网站| 武侠古典久久婷婷狼人伊人| 久久久久亚洲精品男人的天堂| 国产成人久久精品二区三区| 久久精品国产99国产精品澳门| 久久精品无码专区免费青青| 欧美午夜精品久久久久免费视| 亚洲AV无码成人网站久久精品大| 18岁日韩内射颜射午夜久久成人| 亚洲精品美女久久777777| 性欧美丰满熟妇XXXX性久久久 |