差分

ナビゲーションに移動 検索に移動

Xamarin.Mac/スクリーンキャプチャを撮る

6,387 バイト追加, 2015年10月17日 (土) 08:10
ページの作成:「==概要== Xamarin.MacMonoMacMac OS Xのスクリーンキャプチャを撮る。 これができるとHyperDockみたいなアプリを実現で...」
==概要==
[[Xamarin.Mac]]や[[MonoMac]]で[[Mac OS X]]のスクリーンキャプチャを撮る。

これができると[[HyperDock]]みたいなアプリを実現できるかもしれない。
買った方が安いけどね。

[[職業プログラマ]]であれば[[エビデンス]]を取得するのに活躍するかもしれないが、そんな[[フリーソフト]]はすでに山のようにある。
しかも、猫も杓子もウェブアプリかウェブAPIとスマホアプリばかりで、[[Windows]]の案件ですら壊滅している現状で[[Mac]]のアプリなど需要あるのかって話でもある。
そんな細かいことを気にしてはならない。
[[MonoMac]]が流行ればそれでよし。

==実装:スクリーン全体のキャプチャを撮る==
スクリーン全体のキャプチャを撮るにはCore GraphicsフレームワークのCGDisplayCreateImageメソッドを用いる。
Xamarin.Mac (Classic API)にはCGDisplay◯◯◯◯系のAPIがないようなのでP/Invokeで直叩きしている。

このメソッドに渡すスクリーンIDはNSScreen.DeviceDescription["NSScreenNumber"]から簡単に取得できる。
本来であればCGGetActiveDisplayListメソッドで取得するらしいが直叩きするのは面倒なので上記でいいと思われる。

<source lang="csharp">
using System;
using System.Drawing;
using System.Runtime.InteropServices;
using MonoMac.Foundation;
using MonoMac.AppKit;
using MonoMac.CoreGraphics;

namespace ScreenCapture
{
public static class CGDisplay
{
public const string DllName = "/System/Library/Frameworks/CoreGraphics.framework/CoreGraphics";

[DllImport(DllName)]
extern static IntPtr CGDisplayCreateImage(UInt32 displayId);

[DllImport(DllName)]
extern static void CFRelease(IntPtr handle);

public static CGImage CreateImage(UInt32 displayId)
{
IntPtr handle = IntPtr.Zero;

try
{
handle = CGDisplayCreateImage(displayId);
return new CGImage(handle);
}
finally
{
if (handle != IntPtr.Zero)
{
CFRelease(handle);
}
}
}
}

class MainClass
{
static void Main(string[] args)
{
NSApplication.Init();

var id1 = (NSNumber)NSScreen.MainScreen.DeviceDescription["NSScreenNumber"];

using (var cgImage = CGDisplay.CreateImage(id1.UInt32Value))
using (var nsImage = new NSImage(cgImage, new SizeF(cgImage.Width, cgImage.Height)))
using (var nsdata = nsImage.AsTiff())
{
nsdata.Save("/tmp/ScreenCapture.tiff", atomically:true);
}
}
}
}
</source>

==実装:ウインドウのキャプチャを撮る==
[[Xamarin.Mac]]には標準でCGImageクラスにScreenImageという便利な静的メソッドが用意されている。
これを呼ぶだけである。
<source lang="csharp">
public static CGImage ScreenImage(int windownumber, RectangleF bounds);
</source>

引数windownumberは以下の方法で取得した連想配列の「kCGWindowNumber」を使用している。
こちらはXamarin.Mac (Classic API)にはCGWindow◯◯◯◯系のAPIがないようなのでP/Invokeで直叩きしている。
P/Invokeしなくても取得できる方法があるのかもしれないが知らない。
*[[Xamarin.Mac/ウインドウの一覧を取得する]]

引数boundsは取得する範囲を指定する。ウインドウ全体をキャプチャするには「RectangleF.Empty」を指定する。
Xamarin.Mac (Unified API)ではRectangleFはCGRectに置き換えられているので適宜読み替えること。
<source lang="csharp">
var cgImage = CGImage.ScreenImage(windowNumber, RectangleF.Empty)
</source>

以下に開いているウインドウを列挙してキャプチャするサンプルをメモしておく。
<source lang="csharp">
using System;
using System.Runtime.InteropServices;
using System.Drawing;
using MonoMac.Foundation;
using MonoMac.AppKit;
using MonoMac.CoreGraphics;

public static class CGWindow
{
public const string DllName = "/System/Library/Frameworks/CoreGraphics.framework/CoreGraphics";

[DllImport(DllName)]
extern static IntPtr CGWindowListCopyWindowInfo(CGWindowListOption option, UInt32 relativeToWindow);

[DllImport(DllName)]
extern static void CFRelease(IntPtr cf);

public static NSDictionary[] GetWindowList(CGWindowListOption option, UInt32 relativeToWindow = 0)
{
IntPtr handle = IntPtr.Zero;

try
{
handle = CGWindow.CGWindowListCopyWindowInfo(option, relativeToWindow);
return NSArray.ArrayFromHandle<NSDictionary>(handle);
}
finally
{
if (handle != IntPtr.Zero)
{
CFRelease(handle);
}
}
}
}

class MainClass
{
static void Main(string[] args)
{
NSApplication.Init();

var windows = CGWindow.GetWindowList(CGWindowListOption.All);
foreach (var window in windows)
{
Console.WriteLine(window);

var isOnscreen = window["kCGWindowIsOnscreen"];
if (isOnscreen != null)
{
var windowName = ((NSString)window["kCGWindowName"]).ToString();
var windowNumber = ((NSNumber)window["kCGWindowNumber"]).Int32Value;

using (var cgImage = CGImage.ScreenImage(windowNumber, RectangleF.Empty))
using (var nsImage = new NSImage(cgImage, new SizeF(cgImage.Width, cgImage.Height)))
using (var nsData = nsImage.AsTiff())
{
var error = null as NSError;
var filename = string.Format("/tmp/img_{0:D5}_{1}.tiff", windowNumber, windowName);
nsData.Save(file: filename, auxiliaryFile: false, error: out error);
}
}
}
}
}
</source>

==関連項目==
*[[Xamarin.Mac/ウインドウの一覧を取得する]]
*[[Xamarin.Mac/CGImageをNSImageに変換する]]
*[[Xamarin.Mac/CGImageをファイルに保存する]]

==参考文献==
{{reflist}}

{{stub}}

[[category:Xamarin.Mac]]
[[category:MonoMac]]
匿名利用者

案内メニュー