web-dev-qa-db-ja.com

ウィンドウのスクリーンショットと、その上のすべてのウィンドウをキャプチャするにはどうすればよいですか?

GUIソフトウェアの回帰テストとしてスクリーンショットを使用しています。各新しいバージョンを展開する前に、一連の自動タスクが古いバージョンと新しいバージョンに対して実行され、両方の場合で各コマンドの後にスクリーンショットが生成され、結果が比較されます。 ImageMagickのインポートコマンドは、そのために非常にうまく機能しています。

最近、右クリックメニューを追加しました。残念ながら、import -window 'id'はこれらのメニューをキャプチャしません。

Ubuntuのどのコマンドラインツールがウィンドウのスクリーンショットを取り、その上のすべてのウィンドウを撮ることができますか?

つまり、どのツールが、ウィンドウIDに対応するウィンドウのスクリーンショットを撮る代わりに、画面全体のスクリーンショットを撮って、指定されたウィンドウの境界に切り捨てます

スクリーンショットを撮るための端末コマンドは何ですか? にリストされているツールのいずれでも、この結果を簡単な方法で取得できませんでした。

4
Clément

import-screenオプションとともに使用します。たとえば

import -screen -window 'id' test.png
4
Florian Diesch

shutterおよびwmctrlを使用すると、 このスクリプト の編集バージョンは、説明したとおりになります。the area、aウィンドウが(部分的に)他のウィンドウの下にあるかどうか、およびその方法に関係なく、画面上の特定のウィンドウカバー。

スクリーンショットに含まれるウィンドウの周囲のmargeは任意です。必要に応じてゼロに設定します。

実際には

  • 画面にInkscapeウィンドウがあり、IDは0x0520000eで、部分的にいくつかのgeditウィンドウで覆われています。
  • 引数としてウィンドウの周りのウィンドウIDとマージ(px内)を使用してスクリプトを実行します。

    python3 <script> 0x0520000e 10 10 10 10 
    

    (ここで、10 10 10 10は、左/右/上/下のウィンドウの周囲のpxのマージです。画像にマージしないように0に設定します)

    結果:

    enter image description here

スクリプト

#!/usr/bin/env python3
import subprocess
import time
import sys

"""
On different window managers, the window geometry as output of wmctrl differs slightly.
The "deviation" should compensate these differences. Most likely appropriate (tested) settings:
Unity: 0, Gnome: -36, Xfce (Xubuntu): -26, KDE (Kubuntu): 0
"""
#---
deviation = 0
#---

get = lambda cmd: subprocess.check_output(["/bin/bash", "-c", cmd]).decode("utf-8")
time.sleep(0.5)
# targeted window
target = sys.argv[1]; arg = sys.argv[2:]
f_data = [l.split() for l in get("wmctrl -lG").splitlines() if target in l][0][2:6]
xt_data = get("xprop -id "+target).split()
xt_i = xt_data.index("_NET_FRAME_EXTENTS(CARDINAL)")
xt = [int(n.replace(",", "")) for n in xt_data[xt_i+2:xt_i+6]]
# set data for screenshot command
x = str(int(f_data[0])-int(arg[0])-xt[0])
y = str(int(f_data[1])-int(arg[2])-xt[2]+deviation)
w = str(int(f_data[2])+int(arg[0])+int(arg[1])+xt[0]+xt[1])
h = str(int(f_data[3])+int(arg[3])+int(arg[2])+xt[2]+xt[3])

command = "shutter -s="+(",").join([x,y,w,h])+" -e"
subprocess.call(["/bin/bash", "-c", command])

使い方

  • スクリプトはShutterwmctrlを使用します。

    Sudo apt-get install wmctrl shutter
    
  • 以下のスクリプトを空のファイルにコピーし、custom_screenshot.pyとして保存します。

  • 次のコマンドで実行します:

    python3 /path/to/custom_screenshot.py <window_id> <left> <right> <top> <bottom>
    

    ここで、<left> <right> <top> <bottom>は、 this answer。 のように、ウィンドウの周囲の画像に保持したいマージです。

    コマンド例:

    python3 /path/to/custom_screenshot.py 0x0520000e 20 20 20 20
    

説明

  • Shutterでは、デスクトップの定義された領域のスクリーンショットを撮ることができます。

  • 引数としてウィンドウIDを使用して、スクリプトはwmctrl(正確にはwmctrl -lG)の助けを借りてウィンドウの正確な位置を検索し、xprop -id <window_id>の出力(行_NET_FRAME_EXTENTS(CARDINAL) = 0, 0, 28, 0例)。

  • その後、任意のマージで、見つかった領域からスクリーンショットが取得されます。

注意

スクリプトしないは既存のスクリーンショットを上書きします。新しいスクリーンショットの名前は次のとおりです。

outputfile_1.png
outputfile_2.png
outputfile_3.png

等々...


編集

あなたがコメントで速度が問題であると述べたので:

このスクリプト に基づいて、まったく同じトリックを行うが、Scrotの代わりにShutterを使用すると、sleep 0.5をスキップして作成できますたくさん高速:

スクリプト

#!/usr/bin/env python3
import subprocess
import sys
import os

"""
On different window managers, the window geometry as output of wmctrl differs slightly.
The "deviation" should compensate these differences. Most likely appropriate (tested) settings:
Unity: 0, Gnome: -36, Xfce (Xubuntu): -26, KDE (Kubuntu): 0
"""
#---
deviation = 0
#---

get = lambda cmd: subprocess.check_output(["/bin/bash", "-c", cmd]).decode("utf-8")
# targeted window
target = sys.argv[1]; arg = sys.argv[2:]
f_data = [l.split() for l in get("wmctrl -lG").splitlines() if target in l][0][2:6]
xt_data = get("xprop -id "+target).split()
xt_i = xt_data.index("_NET_FRAME_EXTENTS(CARDINAL)")
xt = [int(n.replace(",", "")) for n in xt_data[xt_i+2:xt_i+6]]
# set data for screenshot command
x = str(int(f_data[0])-int(arg[0])-xt[0])
y = str(int(f_data[1])-int(arg[2])-xt[2]+deviation)
w = str(int(f_data[2])+int(arg[0])+int(arg[1])+xt[0]+xt[1])
h = str(int(f_data[3])+int(arg[3])+int(arg[2])+xt[2]+xt[3])

# setting default directories / filenames
home = os.environ["HOME"]
temp = home+"/"+".scrot_images"
img_in = temp+"/in.png"
# if you prefer, you can change the two line below:
output_directory = home+"/"+"scrot_images" # output directory
filename = "outputfile"                    # filename
# creating needed directories
for dr in [temp, output_directory]:
    if not os.path.exists(dr):
        os.mkdir(dr)
# creating filename (-number) to prevent overwriting previous shots
n = 1
while True:
    img_out = output_directory+"/"+filename+"_"+str(n)+".png"
    if os.path.exists(img_out):
        n = n+1
    else:
        break
# Take screnshot, crop image
subprocess.call(["scrot", img_in])
subprocess.Popen(["convert", img_in, "-crop", w+"x"+h+"+"+x+"+"+y, "+repage", img_out])

使用するには

最初のスクリプトとまったく同じように使用します。

  • このスクリプトには、scrotimagemagick、およびwmctrlが必要です

    Sudo apt-get install imagemagick wmctrl scrot
    
  • 画像は~/scrot_imagesに保存されます

説明

最初のスクリプトはShutterのコマンドラインオプションを使用してデスクトップの定義済みセクションを撮影しますが、Scrotはそれをサポートしません。 全画面のスクリーンショットのみを取得します。

ただし、imagemagickのオプションを組み合わせて、画像を取り出して、最初のスクリプトで使用した正確なウィンドウの座標を見つけて、それに応じて画像をトリミングする方法を使用できます。
Scrotは非常に軽量で高速であり、imagemagickのトリミングアクションと組み合わせても、ウィンドウの領域のスクリーンショットを作成する非常に高速な方法があります。

まだ十分に速くない?

必要かどうかはわかりませんが、少し書き直すと(下記のスクリプトを参照)、最初にシリーズ全体を撮影することで一連のショットをさらに速くすることが可能になりますthen(その後)doトリミング。ウィンドウがその位置にとどまると仮定すると、これはかなりの時間を節約します:

  • Scrotのみで撮影(トリミングなし):

    real    0m0.263s
    user    0m0.205s
    sys     0m0.037s
    
  • トリミングを含む撮影:

    real    0m0.363s
    user    0m0.293s
    sys     0m0.040s
    

連続撮影

最後に、一連のスクリーンショットを作成する例として、EDITで提案されている以下のスクリプトを使用します。
これはfirstすべての画像を連続して撮影します。thenは作成されたすべての画像を一度にトリミングします。

2番目のようなスクリプトを使用しますが、1つの追加の引数:連続したシュートの数、たとえば:

python3 /path/to/custom_screenshot.py 0x0520000e 0 0 0 0 20

ウィンドウ0x0520000eの20個のスクリーンショットを連続して(数百個も)作成するために、ウィンドウの周囲をマージしません。

スクリプト

#!/usr/bin/env python3
import subprocess
import sys
import os

"""
On different window managers, the window geometry as output of wmctrl differs slightly.
The "deviation" should compensate these differences. Most likely appropriate (tested) settings:
Unity: 0, Gnome: -36, Xfce (Xubuntu): -26, KDE (Kubuntu): 0
"""
#---
deviation = 0
#---

get = lambda cmd: subprocess.check_output(["/bin/bash", "-c", cmd]).decode("utf-8")
# targeted window
target = sys.argv[1]; arg = sys.argv[2:]
f_data = [l.split() for l in get("wmctrl -lG").splitlines() if target in l][0][2:6]
xt_data = get("xprop -id "+target).split()
xt_i = xt_data.index("_NET_FRAME_EXTENTS(CARDINAL)")
xt = [int(n.replace(",", "")) for n in xt_data[xt_i+2:xt_i+6]]
# set data for screenshot command
x = str(int(f_data[0])-int(arg[0])-xt[0])
y = str(int(f_data[1])-int(arg[2])-xt[2]+deviation)
w = str(int(f_data[2])+int(arg[0])+int(arg[1])+xt[0]+xt[1])
h = str(int(f_data[3])+int(arg[3])+int(arg[2])+xt[2]+xt[3])
# setting default directories / filenames
home = os.environ["HOME"]
temp = home+"/"+".scrot_images"
# if you prefer, you can change the two line below:
output_directory = home+"/"+"scrot_images" # output directory
filename = "outputfile"                    # filename
# creating needed directories
for dr in [temp, output_directory]:
    if not os.path.exists(dr):
        os.mkdir(dr)
# do the shooting
t = 0; l = []; shots = int(sys.argv[6])
while t < shots:
    img_temp = temp+"/"+str(t)+"in.png"
    l.append(img_temp)
    # reading arguments,arranging commands to perform
    subprocess.call(["scrot", img_temp])
    t += 1
# do the cropping on all images in a row
for img in l:
    n = 1
    while True:
        img_out = output_directory+"/"+filename+"_"+str(n)+".png"
        if os.path.exists(img_out):
            n = n+1
        else:
            break
    subprocess.call(["convert", img , "-crop", w+"x"+h+"+"+x+"+"+y, "+repage", img_out])
6
Jacob Vlijm