MFC下截圖 灰度顯示

2021-03-31 08:57:00 字數 2701 閱讀 8212

用mfc很容易把當前螢幕擷取,並顯示在自己程式的ui上。以對話方塊為例,在執行繪製的單元(比如onpaint)中呼叫下面這個函式就能做到:

bool csrnshotdlg::getmyscreen(

cdc *pdc//

目標dc

)

接下來改造一下,把螢幕截圖先轉換為灰度(gray scale)圖,再顯示出來。轉換灰度圖的公式是,對乙個rgb值,r、g、b分別是其3色分量,計算:

gray = r * 0.299 + g *0.587 + b * 0.114

然後將gray分別替換掉原來的3色分量。到這個地方,很自然想到用setpixel/getpixel來實現。因為要對dc進行操作,當然就不能直接在上面getmyscreen裡邊的dc直接操作了,為此對getmyscreen進行一下改造,並且,為了程式的可讀性,增加乙個converttogray函式負責轉換(與上面**不同的地方用紅色區分):

void converttogray (cdc * pdc)

}

bool csrnshotdlg::getmyscreen(

cdc *pdc//

目標dc

)

效果出來了,但是並不完美。實際上我用setpixelv代替了setpixel,但顯示的速度還是很慢,cpu使用率也很高。如何提高效率呢?直接改dc上附著的點陣圖資料似乎是個好辦法。下面就轉而對cbitmap類物件進行操作。

因為是直接截圖,所以需要先用cdc::getdevicecaps帶bitspixel引數獲得螢幕色深,因為不同色深的點陣圖的儲存方式不同。簡要說明一下:16位色位圖,每個象素佔2位元組;24位色,每個象素佔3位元組;32位色,每個象素佔4位元組儲存空間。我們可以用cbitmap::getbitmapbits函式來獲得位圖資料,這其實是乙個byte陣列。這個陣列的結構,最簡單的是24位色的情況。前面說過了每個象素佔3個位元組,按陣列下標從低到高分別是b、g、r這3色分量,而32位色的情況跟24位色類似,4個位元組只不過多了乙個alpha值。下面就是處理24位色深的converttogray24。

#define bits24(int)(1024 * 768 * 3)

void converttogray24(cbitmap *pbmp)

pbmp->setbitmapbits(bits24, lpbits);

delete lpbits;

}

當getdevicecaps(bitspixel)返回16的時候,又有兩種情況:16位色和15位色。16位色的情況下,位圖陣列使用2位元組儲存資料,其中從高位往低位分別是b、g、r這3色分量按位5:6:5占用。需要用位操作來獲得每個分量的色值:

#define getrvaluex(rgb)((byte)(rgb) & 0x1f)

#define getgvaluex(rgb)((byte)(((rgb) & 0x07e0) >> 5))

#define getbvaluex(rgb)((byte)(((rgb) & 0xf800) >> 11))

#define rgbx(r,g,b) /

((word)(((byte)(r)|((word)((byte)(g))<<5))|(((word)(byte)(b))<<11)))

要注意的是因為綠色分量占用了6bit,其儲存精度是其它兩個分量的2倍,所以在進行後繼的計算的時候公式的因數會有所改變。(另外,使用15位色的介面卡比較少,其儲存規則也是占用2位元組,但是最高位無意義,其餘15位按5:5:5分配,這裡不詳細討論了。)

#define bits16(int)(1024 * 768 * 2)

void converttogray16(cbitmap *pbmp)

pbmp->setbitmapbits(bits16, lpbits);

delete lpbits;

}

最後,第三次改造getmyscreen:

bool csrnshotdlg::getmyscreen(

cdc *pdc//

目標dc

)

pbmp->create***patiblebitmap(&dc, clientrect.width(),clientrect.height());

pmemdc->selectobject(pbmp);

showwindow(sw_hide);

pmemdc->bitblt(0, 0,

clientrect.width(), clientrect.height(),

&dc, 0, 0, srccopy);

switch(pmemdc->getdevicecaps(bitspixel))

pdc->bitblt(0, 0, //

起始位置

clientrect.width(),clientrect.height(),//

寬高 pmemdc, //

源cdc

物件 0, 0,

// 源位置

srccopy//

複製方法

);

pbmp->deleteobject();

pmemdc->deletedc();

delete pbmp;

delete pmemdc;

dc.deletedc();

return true;

}

附,感謝puhuofeie的幫助

Linux下截圖方法!

一 最便捷的方法 1 按下印螢幕鍵,擷取整個桌面 2 按下alt 螢幕鍵,擷取當前視窗 二 命令列截圖 1 import screenshot.jpg 你將可以使用滑鼠選取乙個矩形框。在你放下滑鼠左鍵的那一刻,乙個該矩形框的截圖會以import後面 跟的檔名儲存在當前目錄下。2 scrot d 4 ...

雙屏 多顯示器截圖

截圖程式的原始碼網上到處都有,但是基本都不支援多顯示器。這讓我一度以為支援多顯示器是一件很困難的事情。demo 包含多顯示器支援,視窗高亮,十字放大等 其實多顯示的截圖跟主顯示器的截圖區別並不大,甚至根本不需要enumdisplaymonitors 之類的呼叫。只是因為網上有了原始碼,我們就懶得想了...

Windows Mobile下快速截圖的一種方法

wince下截圖的方法有很多種,這裡介紹一種利用gapi實現的方法。gapi是game api的縮寫,它提供了一系列函式,可以直接對螢幕緩衝區進行讀 寫訪問。雖然現在逐漸被directx mobile取代,但自從2000年首次應用在ppc上後,幾乎所有的移動裝置上都能看見它。gapi主要應用於遊戲開...