astel-labs.net

C#などのプログラミングTipsや雑記をつらつらと書くかもしれないブログです。

  • Home
RSS

WPF – SnippingTool っぽい物を作ってみた

Posted on 2012年7月21日 by Nymphaea
No CommentsLeave a comment

SnippingTool ってなんだろう? と思う方も多いのかもしれませんが、「Microsoft 拡張パック for Windows XP Tablet PC Edition」やStarter と Home Basic を除くエディションの Windows Vista と Windows 7 に標準で含まれている、指定した画面上の部分的な範囲のスクリーンショットを切り取るツールです。

こんなツール。通常はスタートメニューの「アクセサリ」直下にあります。

このツールを実行してみるとわかるのですが、以下のような感じで簡単にスクリーンショットをとることができます。
マウスで切り取りたい範囲をドラッグすると赤枠で囲まれた範囲が透過します。

これと同様の機能が Excel 2010 にもあります。
この機能には大変お世話になっています。

 

で、これらのツールを使っていて矩形の中を透過させるにはどうすればいいのかをふと考えて、だいぶ前にサンプルとしてコードを組んでみたものです。
WPF を使うことで、ものすごく簡単にこのようなことができることがわかると思います。

まずは表示側となる Xaml です。

<Window x:Class="TrimScreen.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        WindowStyle="None" Topmost="True"
        Margin="0" Padding="0" AllowsTransparency="True"
        Background="Transparent" ShowInTaskbar="False" Title="MainWindow"
        Loaded="Window_Loaded">
    <Canvas Name="LayoutRoot" Background="Transparent" Margin="0">
        <Path Stroke="Black" StrokeThickness="1" Fill="#BBFFFFFF"
              Margin="0"
              MouseLeftButtonDown="DrawingPath_MouseLeftButtonDown"
              MouseLeftButtonUp="DrawingPath_MouseLeftButtonUp"
              MouseMove="DrawingPath_MouseMove">
            <Path.Data>
                <CombinedGeometry x:Name="ScreenArea" GeometryCombineMode="Xor" />
            </Path.Data>
        </Path>
    </Canvas>
</Window>

見てもらうとわかるように、Canvas 上に Path を配置して CombinedGeometry で Xor を指定しています。
つまり、Xor を使うと重なり合った部分を切り取ることができるため、矩形の中を透明に表示することができます。

続いてはソースコードです。

using System;
using System.Reflection;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Shapes;

namespace TrimScreen
{
    /// <summary>
    /// MainWindow.xaml の相互作用ロジック
    /// </summary>
    public partial class MainWindow : Window
    {
        private Point _position;
        private bool _trimEnable = false;

        public MainWindow()
        {
            InitializeComponent();
        }

        private void Window_Loaded( object sender, RoutedEventArgs e )
        {
            // プライマリスクリーンサイズの取得
            var screen = System.Windows.Forms.Screen.PrimaryScreen;

            // ウィンドウサイズの設定
            this.Left = screen.Bounds.Left;
            this.Top = screen.Bounds.Top;
            this.Width = screen.Bounds.Width;
            this.Height = screen.Bounds.Height;

            // ジオメトリサイズの設定
            this.ScreenArea.Geometry1 = new RectangleGeometry( new Rect( 0, 0, screen.Bounds.Width, screen.Bounds.Height ) );
        }

        private void DrawingPath_MouseLeftButtonDown( object sender, MouseButtonEventArgs e )
        {
            var path = sender as Path;
            if( path == null )
                return;

            // 開始座標を取得
            var point = e.GetPosition( path );
            _position = point;

            // マウスキャプチャの設定
            _trimEnable = true;
            this.Cursor = Cursors.Cross;
            path.CaptureMouse();
        }

        private void DrawingPath_MouseLeftButtonUp( object sender, MouseButtonEventArgs e )
        {
            var path = sender as Path;
            if( path == null )
                return;

            // 現在座標を取得
            var point = e.GetPosition( path );

            // マウスキャプチャの終了
            _trimEnable = false;
            this.Cursor = Cursors.Arrow;
            path.ReleaseMouseCapture();

            // 画面キャプチャ
            CaptureScreen( point );

            // アプリケーションの終了
            this.Close();
        }

        private void DrawingPath_MouseMove( object sender, MouseEventArgs e )
        {
            if( !_trimEnable )
                return;

            var path = sender as Path;
            if( path == null )
                return;

            // 現在座標を取得
            var point = e.GetPosition( path );

            // キャプチャ領域枠の描画
            DrawStroke( point );
        }

        private void DrawStroke( Point point )
        {
            // 矩形の描画
            var x = _position.X < point.X ? _position.X : point.X;
            var y = _position.Y < point.Y ? _position.Y : point.Y;
            var width = Math.Abs( point.X - _position.X );
            var height = Math.Abs( point.Y - _position.Y );
            this.ScreenArea.Geometry2 = new RectangleGeometry( new Rect( x, y, width, height ) );
        }

        private void CaptureScreen( Point point )
        {
            // 座標変換
            var start = PointToScreen( _position );
            var end = PointToScreen( point );

            // キャプチャエリアの取得
            var x = start.X < end.X ? (int)start.X : (int)end.X;
            var y = start.Y < end.Y ? (int)start.Y : (int)end.Y;
            var width = (int)Math.Abs( end.X - start.X );
            var height = (int)Math.Abs( end.Y - start.Y );
            if( width == 0 || height == 0 )
                return;

            // スクリーンイメージの取得
            using( var bmp = new System.Drawing.Bitmap( width, height, System.Drawing.Imaging.PixelFormat.Format24bppRgb ) )
            using( var graph = System.Drawing.Graphics.FromImage( bmp ) ) {
                // 画面をコピーする
                graph.CopyFromScreen( new System.Drawing.Point( x, y ), new System.Drawing.Point(), bmp.Size );

                // イメージの保存
                string folder = System.IO.Path.GetDirectoryName( Assembly.GetExecutingAssembly().Location );
                bmp.Save( System.IO.Path.ChangeExtension( System.IO.Path.Combine( folder, "image" ), "png" ), System.Drawing.Imaging.ImageFormat.Png );
            }
        }
    }
}

一応、画面をキャプチャするところまで実装したためコード量が多いように見えますが、矩形を切り抜く処理は数行程度です。
また、キャプチャ処理は本題ではないので簡単な方法で済ませていますので悪しからず…
キャプチャした画像は実行ファイルがある場所に作成されます。

なんの役に立つのかはよくわからないサンプルですが、WPF をつかうと WindowForms の時にはものすごい量のコードを書く必要があったものが、ほんの数行でかけることがわかると思います。

Categories: C#, WPF, プログラミング

 

DebuggerVisualizer アドインの作成
WPF – 文字の縁取りをする

コメントを残す

コメントを投稿するにはログインしてください。

  • 2012年7月
    日 月 火 水 木 金 土
    1234567
    891011121314
    15161718192021
    22232425262728
    293031  
    « 5月   11月 »
  • 最近の投稿

    • raspberry pi に nginx をセットアップする
    • VSCode を日本語化する
    • raspberry pi に VSCode をインストールする
    • WindowsのプロダクトIDを取得する
    • SQL Server – money型とdecimal型を併用した金額計算
  • アーカイブ

    • 2020年3月
    • 2016年12月
    • 2014年6月
    • 2014年5月
    • 2013年7月
    • 2012年11月
    • 2012年7月
    • 2012年5月
    • 2012年4月
    • 2011年4月
    • 2011年1月
    • 2010年11月
    • 2010年10月
    • 2010年9月
    • 2010年8月
    • 2010年7月
    • 2010年6月
    • 2010年5月
    • 2010年4月
  • カテゴリー

    • C#
    • jQuery
    • OpenCV
    • raspberry pi
    • SharePoint
    • Silverlight
    • SQL Server
    • WCF
    • WPF
    • プログラミング
    • 未分類
    • 雑記
© astel-labs.net. Proudly Powered by WordPress | Nest Theme by YChong

このブログ内で公開されているソースコードおよびサンプルプログラムに関わるライセンスはすべて修正BSDライセンス(New BSD License)として公開しています。
但し、サンプルプログラムに含まれる外部アセンブリが同様のライセンスとは限りませんので、利用する前に必ずすべてのライセンスの確認を行ってください。