3
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Windows GUIプログラミング入門26 画面キャプチャ

Last updated at Posted at 2020-07-29

■はじめに

今回は画面全体のスクリーンショットを撮り、jpeg画像として保存するアプリケーションを作ります。

■開発環境

  • Windows 10
  • Visual Studio Community 2019 (Version 16.6.5)
  • .NET Framework 4.8 / .NET Core 3.1

■.NET Framework版のみの作業

新しいプロジェクトでWPFアプリ (.NET Framework) C#を選択します。

ソリューションエクスプローラーで参照を右クリックし、参照の追加を選択します。
11.png
アセンブリでSystem.Drawingのチェックボックスをチェックし、OKボタンを選択します。

■.NET Core版のみの作業

新しいプロジェクトでWPF App (.NET Core) C#を選択します。

ソリューションエクスプローラーでプロジェクトを右クリック、NuGetパッケージの管理を選択します。
22.png

System.Drawing.Commonをインストールします。
23.png

■作成(.NET Framework/.NET Core共通)

◇画面

31.png

MainWindow.xaml
<Window
    x:Class="ScreenShot.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:local="clr-namespace:ScreenShotCore"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    Title="キャプチャ"
    Width="640"
    Height="400"
    ResizeMode="CanResizeWithGrip"
    WindowStyle="ToolWindow"
    mc:Ignorable="d">
    <Window.Resources>
        <!-- ボタンの既定スタイル -->
        <Style TargetType="Button">
            <Setter Property="Width" Value="150" />
            <Setter Property="Margin" Value="10" />
            <Setter Property="Padding" Value="5" />
        </Style>
    </Window.Resources>

    <Grid Background="SlateGray">
        <Grid.RowDefinitions>
            <RowDefinition />
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>

        <Viewbox>
            <Image x:Name="CaptureImage" Margin="5" />
        </Viewbox>
        <TextBlock
            x:Name="SaveInfo"
            Margin="10"
            HorizontalAlignment="Center"
            VerticalAlignment="Center"
            FontSize="60"
            Text="保存しました。"
            Visibility="Collapsed" />

        <StackPanel
            Grid.Row="1"
            Background="LightSteelBlue"
            Orientation="Horizontal">
            <Button Click="CaptureButton_Click" Content="キャプチャ(_1)" />
            <Button Click="SaveButton_Click" Content="保存(_2)" />
            <Button Click="CaptureAndSaveButton_Click" Content="キャプチャして保存(_3)" />
        </StackPanel>
    </Grid>
</Window>

◇コード

MainWindow.xaml.cs
using System;
using System.IO;
using System.Threading.Tasks;
using System.Windows;
using DIMG = System.Drawing.Imaging;
using DRW = System.Drawing;
using MIMG = System.Windows.Media.Imaging;

namespace ScreenShot
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        /// <summary>
        /// キャプチャ時、自ウィンドウを隠すための待ち時間
        /// </summary>
        private static readonly int CaptureWaitMSec = 300;

        [System.Runtime.InteropServices.DllImport("gdi32.dll")]
        private static extern bool DeleteObject(IntPtr objectHandle);

        /// <summary>
        /// コンストラクタ
        /// </summary>
        public MainWindow()
        {
            InitializeComponent();
        }

        /// <summary>
        /// キャプチャボタン押下
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private async void CaptureButton_Click(object sender, RoutedEventArgs e)
        {
            CaptureImage.Source = null;
            // ウィンドウ最小化
            WindowState = WindowState.Minimized;
            // ウィンドウが最小化するまで少し待つ
            await Task.Delay(CaptureWaitMSec);
            // キャプチャ
            CaptureImage.Source = GetFullScreenImage();
            // ウィンドウを元に戻す
            WindowState = WindowState.Normal;
        }

        /// <summary>
        /// 保存ボタン押下
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private async void SaveButton_Click(object sender, RoutedEventArgs e)
        {
            if (CaptureImage.Source == null)
            {
                MessageBox.Show("まずキャプチャしてください。", "警告", MessageBoxButton.OK, MessageBoxImage.Warning);
                return;
            }

            // 画像保存
            SaveImage();
            // 保存通知
            await NotifySaveImage();
        }

        /// <summary>
        /// キャプチャして保存ボタン押下
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private async void CaptureAndSaveButton_Click(object sender, RoutedEventArgs e)
        {
            // ウィンドウ最小化
            WindowState = WindowState.Minimized;
            // ウィンドウが最小化するまで少し待つ
            await Task.Delay(CaptureWaitMSec);
            // キャプチャ
            CaptureImage.Source = GetFullScreenImage();
            // 画像保存
            SaveImage();
            // ウィンドウを元に戻す
            WindowState = WindowState.Normal;
            // 保存通知
            await NotifySaveImage();
        }

        /// <summary>
        /// 画面全体のイメージ取得
        /// </summary>
        /// <returns></returns>
        private MIMG.BitmapSource GetFullScreenImage()
        {
            int w = (int)SystemParameters.PrimaryScreenWidth;
            int h = (int)SystemParameters.PrimaryScreenHeight;

            using (var bmp = new DRW.Bitmap(w, h, DIMG.PixelFormat.Format32bppRgb))
            using (var grph = DRW.Graphics.FromImage(bmp))
            {
                // スクリーンイメージをコピー
                grph.CopyFromScreen(
                    sourceX: 0, sourceY: 0,
                    destinationX: 0, destinationY: 0,
                    bmp.Size);

                IntPtr bmpHandle = bmp.GetHbitmap();

                try
                {
                    return System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(
                        bmpHandle,
                        IntPtr.Zero,
                        Int32Rect.Empty,
                        MIMG.BitmapSizeOptions.FromEmptyOptions());
                }
                finally
                {
                    DeleteObject(bmpHandle);
                }
            }
        }

        /// <summary>
        /// 画像ファイルを保存
        /// </summary>
        private void SaveImage()
        {
            // ピクチャフォルダのスクリーンショットフォルダ
            string saveFolder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyPictures), "Screenshots");
            string saveFilePath = Path.Combine(saveFolder, $"スクショ{DateTime.Now:yyyyMMdd-HHmmss}.jpeg");

            if (!Directory.Exists(saveFolder))
            {
                // 保存先フォルダが無ければ作成
                Directory.CreateDirectory(saveFolder);
            }

            // 画像ファイル保存
            using (Stream stream = new FileStream(saveFilePath, FileMode.Create))
            {
                var encoder = new MIMG.JpegBitmapEncoder();
                encoder.Frames.Add(MIMG.BitmapFrame.Create((MIMG.BitmapSource)CaptureImage.Source));
                encoder.Save(stream);
            }
        }

        /// <summary>
        /// 保存通知
        /// </summary>
        /// <returns></returns>
        /// <remarks>
        /// 画像保存メッセージを表示し、画面の画像をクリアする。
        /// </remarks>
        private async Task NotifySaveImage()
        {
            // 保存通知
            SaveInfo.Visibility = Visibility.Visible;
            await Task.Delay(250);
            // 画像クリア
            CaptureImage.Source = null;
            await Task.Delay(250);
            // 保存通知隠す
            SaveInfo.Visibility = Visibility.Collapsed;
        }

    }
}

■実行してみる

41.png

キャプチャボタンを押しました。
一瞬、画面が隠れて全画面のスクリーンショットが画面に表示されます。
42.png

画面のサイズを拡大すると、画像も引き伸ばされます。
43.png

保存ボタンを押すと画面に表示されている画像が「ピクチャ」フォルダの「スクリーンショット」フォルダに保存されます。
45.png

46.png

おしまい


<< 最初の記事   < 前の記事   次の記事 >

3
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?