デスクトップをコピーする

 パソコンを使っていて、特にパソコンの操作方法なんかの資料を作るときに、こんな画面と説明したいことがよくある。そんな時使うのが、キーボードの右側にある『Print Screen』キーです。このキーを押したときと同じ動作をIron Pythonで実行してみましょう。

 まず画面の高さと幅の情報の入手します。

 プログラムってパソコンに仕事をさせるので、難しいことをデジタルに行っているイメージがあると思いますが、それほど難しくありません。大抵はアナログで考えることをデジタルに置き換えれば出来ちゃいます。
 今回の場合、デスクトップを画像として取り込むわけですから、デスクトップの絵を扱うわけです。アナログで考えると絵を描くためには画用紙を準備しますね。じゃあ、どのくらいの大きさの画用紙を準備したらいいでしょうか。それはもちろん描こうとするものに寄りますよね。だから画面の高さと幅の情報を入手します。

 画面の情報を入手するのに使うクラスは、"System.Windows.Forms"の名前空間にあるScreenクラスを使います。
 ScreenクラスのPrimaryScreenプロパティの境界情報(Bounds)から高さ(Height)と幅(Width)の情報を入手します。ではやってみましょう。

import clr
clr.AddReference("System.Windows.Forms")
from System.Windows.Forms import Screen

print "画面の高さは",Screen.PrimaryScreen.Bounds.Height
print "画面の幅は",Screen.PrimaryScreen.Bounds.Width

raw_input()

出力画面:
 画面の高さは 800
 画面の幅は 1280
今どきにしては、ちっちゃい画面でしょうか・・・。(笑)

 Bitmapオブジェクトを準備します。

 画面のサイズのが分かったので、スクリプトを準備していきましょう。まず画用紙であるBitmapオブジェクトを準備します。Bitmapクラスは"System.Drawing"の名前空間にあります。

import clr
clr.AddReference("System.Windows.Forms")
clr.AddReference("System.Drawing")
from System.Windows.Forms import Screen
from System.Drawing import Bitmap, Graphics, Point

#Bitmapオブジェクト"bmp"を準備します。
bmp = Bitmap(Screen.PrimaryScreen.Bounds.Width,
       Screen.PrimaryScreen.Bounds.Height)

 上記ではBitmapクラスのほかに、GraphicsクラスやPointクラスも使うので、ついでにimportしておきます。
 さて、せっかくBitmapオブジェクトを準備したわけですが、実はBitmapクラスには画像のサイズや解像度なんかの情報を見たり、bitmapファイルを開いたり保存することはできるんですが、Screenからコピーするメゾットをもっていません。

graph = Graphics.FromImage(bmp)

 上記ではBitmapオブジェクトを元に、直線や曲線の描画なんかを担当するGraphicsオブジェクトを作成します。『デュエルモンスターズ』で融合モンスターを召還する感じでしょうか。(笑)

graph.CopyFromScreen(Point(0,0), Point(0,0), bmp.Size)

 GraphicsクラスのCopyFromScreenメゾットを使って、Screenの情報をBitmapオブジェクトにコピーします。CopyFromScreenメゾットの第1引数はコピー元の左上を指定したPointオブジェクト、第2引数にはコピー先の左上を指定したPointオブジェクトを指定します。今回は全部コピーするだけなのでとちらもPoint(0,0)にします。

 あっ、ちょっとここで覚えておくと便利なことです。パソコンの世界では画面の左上が原点で、横方向をX軸で左から右に数字が増えます。縦方向はY軸で上から下に数字が大きくなります。つまり左上がPoint(0,0)で右下は私のパソコンではPoint(1280,800)になります。中学校で習うY軸とは方向が逆ですね。

 で話を戻して、CopyFromScreenメゾットの第3引数は、コピーするデータのサイズを教えてあげます。Bitmapオブジェクトのbmpは画面サイズを元に作ってるので、bmpのサイズを使えば、教えることが出来ます。

 これでScreenの情報をBitmapオブジェクトにコピーできたので、Graphicsオブジェクトは不要になりました。Graphicsオブジェクトを捨てましょう。

graph.Dispose()

 今までたくさんスクリプトを使ってオブジェクトを作ってきたけど、捨てたことは無かったですね。なんでGraphicsだけ捨てなきゃいけないの?って不思議ですねぇ。
 実はGraphicsオブジェクトはディスプレイの機械とソフトの間を仲介することをやっていて、Windowsからいろいろ優先してもらえる特権をもらっているオブジェクトの一つです。なのでGraphicsオブジェクトが増えてくるとパソコンの動作が遅くなってくる原因になるため、WindowsはGraphicsオブジェクトの作成できる数を制限しています。
 そのためIron PythonがGraphicsオブジェクトを使っているということは、他のプログラムが動作を止めて待っている可能性があります。
 他のプログラムに迷惑を掛けて、パソコン全体の動作を遅くしないように、使い終わったらきちんとGraphicsオブジェクトを捨てた方がよいでしょう。

 以上を踏まえると、Script全体は次のようになります。

import clr
clr.AddReference("System.Windows.Forms")
clr.AddReference("System.Drawing")
from System.Windows.Forms import Screen
from System.Drawing import Bitmap, Graphics, Point

bmp = Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height)
graph = Graphics.FromImage(bmp)
graph.CopyFromScreen(Point(0,0), Point(0,0), bmp.Size)
graph.Dispose()

bmp.Save("Screen.bmp") ←コピーした画像をSaveメゾットを使って保存してます。

print "実行しました。"

raw_input()

Scriptファイルを保存してあるフォルダに"Screen.bmp"が保存されていれば成功です。