天天看點

Linux X11擷取螢幕截圖和程式視窗截圖,并通過QPixmap顯示

最近接手一個項目,需要UOS系統上實作螢幕和視窗捕獲。

由于QT隻提供了螢幕捕獲功能,沒有提供視窗捕獲,于是就找到了老朋友——OBS(畢竟MacOS的螢幕捕獲也是扒的OBS代碼)。

幸運的是,UOS系統商店自帶OBS,直接省去了編譯環節。

Linux X11擷取螢幕截圖和程式視窗截圖,并通過QPixmap顯示
Linux X11擷取螢幕截圖和程式視窗截圖,并通過QPixmap顯示
Linux X11擷取螢幕截圖和程式視窗截圖,并通過QPixmap顯示

從上圖可以看出,OBS自帶螢幕捕獲和視窗捕獲,視窗捕獲也可以擷取目前桌面上打開的頁面。

試用了一下,視窗捕獲時最小化視窗,會導緻程式卡死,也就是說最小化時擷取不到圖像。問題不大,能用就行。

看了一下obs源碼,相關代碼在plugins->linux-capture裡。

Linux X11擷取螢幕截圖和程式視窗截圖,并通過QPixmap顯示

用到的主要是X11庫。

整理了一下obs和網上的代碼,實作螢幕捕獲+視窗捕獲。

包含頭檔案

調用庫,在xx.pro檔案裡添加

視窗列舉、擷取視窗名稱

将視窗顯示到QListWidget中

擷取整個螢幕圖像并顯示到QListWidget中

可以看出螢幕截圖跟視窗截圖的差別就是擷取Window參數方法不同。使用XGetImage擷取圖像完全相同。

再進一步觀察可以發現,在擷取視窗Window時,先調用 RootWindow 擷取目前螢幕的Window,然後使用 XGetWindowProperty 擷取目前螢幕下的所有視窗。

最終實作效果:

Linux X11擷取螢幕截圖和程式視窗截圖,并通過QPixmap顯示

捕獲到了Desktop和QT這兩個程式的視窗圖像,以及整個螢幕的圖像。

但是Desktop為什麼是黑的?

原來XGetImage擷取到的是視窗的可見部分,運作程式時,QT處于最大化,把整個Desktop都擋住了,擷取到的圖像就是全黑的,把QT縮小以後在運作一遍試試。

Linux X11擷取螢幕截圖和程式視窗截圖,并通過QPixmap顯示

DDE Dock是dock欄的圖像,被拉伸以後就這麼奇怪。

可以看出Desktop頁面也顯示出來了,并且Dock欄和QT遮擋住的部分是黑色。

程式目标可以說達成一半了。

順便說一個程式運作時出現的崩潰錯誤

Linux X11擷取螢幕截圖和程式視窗截圖,并通過QPixmap顯示

Debug發現程式崩潰在XImage轉QImage這裡。傳來的XImage是一個空指針,導緻程式崩潰。

 QImage image = QImage((const uchar *)(pImage->data), pImage->width, pImage->height, pImage->bytes_per_line, QImage::Format_RGB32); 

崩潰在QT Creator視窗,當時的情況是

Linux X11擷取螢幕截圖和程式視窗截圖,并通過QPixmap顯示

當我把QT最大化或者移動到桌面最中間時,程式又能正常運作了。

經過反複試驗得出了一個結論,如果視窗有一部分位于螢幕外,XGetImage就會傳回空指針。

修改一下代碼,隻截屏顯示在桌面的部分,截去在螢幕外的部分

發現還是會崩潰,調試發現attrs.x和attrs.y永遠都是0,并不是視窗的實際坐标。

谷歌一下才知道,要想擷取目前視窗在螢幕上的坐标,需要用 XTranslateCoordinates 轉換一下

x和y就是視窗的實際坐标。

改一下代碼,運作成功

Linux X11擷取螢幕截圖和程式視窗截圖,并通過QPixmap顯示

大功告成(一半)。

對比OBS,OBS可以擷取視窗的完整圖像,哪怕視窗有一部分在螢幕外。還需要繼續研究obs代碼。。。

未完待續。

繼續閱讀